In production (Cloud Run) we are suffering from an intermittent issue where we receive some documents twice from query.stream(). In our production code this reproduces almost 100% of the time and I've been trying to get a locally running example. Unfortunately I cannot get it to reproduce as frequently, but it does fail sometimes.
but this sometimes seems to restart at a point that re-emits 15 documents from the stream that have already been emitted.
I guess there is some buffering going on between the different streams that are set up. According to
object streams have a default of 16 buffered objects and we consistently see 15 re-remitted documents. So it seems some documents are already in some buffer without
knowing about it.
It also appears that there might be multiple stream with 16 buffered elements at play here. After receiving document 58855 the stream resets to 58841 but the actual firestore error from the backend was after receiving 58902 which is even further along in the query.
. If so, shouldn't these first be flushed to the transformer to emit them and increase the
The full logfile is 120MB and a bit much for a github issue attachment. Below is the interesting part where you can see the documents being fetched, the error and then some of the old documents being fetched again:
start counting at 11:36:43
Firestore (4.15.1) 2022-10-22T09:36:43.658Z hGIr6 [ClientPool.acquire]: Re-using existing client with 100 remaining operations
Firestore (4.15.1) 2022-10-22T09:36:43.658Z hGIr6 [Firestore.requestStream]: Sending request: {"parent":"projects/my-project/databases/(default)/documents","structuredQuery":{"from":[{"collectionId":"docs"}],"orderBy":[{"field":{"fieldPath":"foo"},"direction":"ASCENDING"}]}}
Firestore (4.15.1) 2022-10-22T09:36:43.725Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"0","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/OAZ5qSYpo4BV5AsCfpnv","createTime":{"seconds":"1666431351","nanos":352182000},"updateTime":{"seconds":"1666431351","nanos":352182000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:36:43.725Z hGIr6 [Firestore._initializeStream]: Releasing stream
Firestore (4.15.1) 2022-10-22T09:36:43.728Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"1","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/yHrEMsYdSn16z2PmKGXs","createTime":{"seconds":"1666431352","nanos":625035000},"updateTime":{"seconds":"1666431352","nanos":625035000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
<<snip document fetches that increment by 1>>
Firestore (4.15.1) 2022-10-22T09:39:35.951Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58830","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/qbRS5YHY1fyszPIXMmiZ","createTime":{"seconds":"1666431385","nanos":824604000},"updateTime":{"seconds":"1666431385","nanos":824604000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:35.951Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58831","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/6pYE69zRxRu7qdsfadHC","createTime":{"seconds":"1666431385","nanos":997470000},"updateTime":{"seconds":"1666431385","nanos":997470000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:35.951Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58832","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/KBWYahhOECXZLPi8H4cX","createTime":{"seconds":"1666431385","nanos":824641000},"updateTime":{"seconds":"1666431385","nanos":824641000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
<<snip document fetches that increment by 1>>
Firestore (4.15.1) 2022-10-22T09:39:36.095Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58884","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/510PozVyJPme0G9NaVgp","createTime":{"seconds":"1666431385","nanos":997601000},"updateTime":{"seconds":"1666431385","nanos":997601000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.095Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58885","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/1XTErTyO4xli2myqHoib","createTime":{"seconds":"1666431385","nanos":985602000},"updateTime":{"seconds":"1666431385","nanos":985602000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.095Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58886","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/H7BA3pQUiSiVNb0W2yyU","createTime":{"seconds":"1666431386","nanos":11813000},"updateTime":{"seconds":"1666431386","nanos":11813000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.136Z hGIr6 [Firestore._initializeStream]: Received stream error: Error: 14 UNAVAILABLE: The datastore operation timed out, or the data was temporarily unavailable.
at Object.callErrorFromStatus (/Users/***/node_modules/@grpc/grpc-js/src/call.ts:81:24)
at Object.onReceiveStatus (/Users/***/node_modules/@grpc/grpc-js/src/client.ts:577:32)
at Object.onReceiveStatus (/Users/***/node_modules/@grpc/grpc-js/src/client-interceptors.ts:392:48)
at /Users/***/node_modules/@grpc/grpc-js/src/call-stream.ts:299:24
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
code: 14,
details: 'The datastore operation timed out, or the data was temporarily unavailable.',
metadata: Metadata {
internalRepr: Map(1) { 'content-disposition' => [Array] },
options: {}
}
}
Firestore (4.15.1) 2022-10-22T09:39:36.136Z hGIr6 [Firestore._initializeStream]: Received stream end
Firestore (4.15.1) 2022-10-22T09:39:36.137Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58887","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/6ZtkdHXPorN2WxT39LfI","createTime":{"seconds":"1666431385","nanos":997529000},"updateTime":{"seconds":"1666431385","nanos":997529000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.137Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58888","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/IubZjcNfasAN252kahPv","createTime":{"seconds":"1666431385","nanos":410388000},"updateTime":{"seconds":"1666431385","nanos":410388000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.137Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58889","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/VuQ6weH1v7Mg8WmvJsR7","createTime":{"seconds":"1666431386","nanos":94746000},"updateTime":{"seconds":"1666431386","nanos":94746000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
<<snip document fetches that increment by 1>>
Firestore (4.15.1) 2022-10-22T09:39:36.137Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58900","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/M6W35EBBQ2NXUM7G2Y2l","createTime":{"seconds":"1666431385","nanos":682013000},"updateTime":{"seconds":"1666431385","nanos":682013000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.137Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58901","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/u1wvtsmGkSZ4b7sDzEZr","createTime":{"seconds":"1666431385","nanos":273555000},"updateTime":{"seconds":"1666431385","nanos":273555000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.137Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58902","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/dvT6jdErVuIJs3x5bx68","createTime":{"seconds":"1666431385","nanos":681961000},"updateTime":{"seconds":"1666431385","nanos":681961000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.137Z hGIr6 [Query._stream]: Query failed with retryable stream error: Error: 14 UNAVAILABLE: The datastore operation timed out, or the data was temporarily unavailable.
at Object.callErrorFromStatus (/Users/***/node_modules/@grpc/grpc-js/src/call.ts:81:24)
at Object.onReceiveStatus (/Users/***/node_modules/@grpc/grpc-js/src/client.ts:577:32)
at Object.onReceiveStatus (/Users/***/node_modules/@grpc/grpc-js/src/client-interceptors.ts:392:48)
at /Users/***/node_modules/@grpc/grpc-js/src/call-stream.ts:299:24
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
code: 14,
details: 'The datastore operation timed out, or the data was temporarily unavailable.',
metadata: Metadata {
internalRepr: Map(1) { 'content-disposition' => [Array] },
options: {}
}
}
Firestore (4.15.1) 2022-10-22T09:39:36.140Z hGIr6 [ClientPool.acquire]: Re-using existing client with 100 remaining operations
Firestore (4.15.1) 2022-10-22T09:39:36.140Z hGIr6 [Firestore.requestStream]: Sending request: {"parent":"projects/my-project/databases/(default)/documents","structuredQuery":{"from":[{"collectionId":"docs"}],"orderBy":[{"field":{"fieldPath":"foo"},"direction":"ASCENDING"},{"field":{"fieldPath":"__name__"},"direction":"ASCENDING"}],"startAt":{"values":[{"integerValue":58840},{"referenceValue":"projects/my-project/databases/(default)/documents/docs/HdA5T5JGI3bv07dIX3hB"}]}},"readTime":{"seconds":"1666431403","nanos":703161000}}
Firestore (4.15.1) 2022-10-22T09:39:36.477Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58841","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/9QlDGznvrnK0mflWtld7","createTime":{"seconds":"1666431386","nanos":44926000},"updateTime":{"seconds":"1666431386","nanos":44926000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.477Z hGIr6 [Firestore._initializeStream]: Releasing stream
Firestore (4.15.1) 2022-10-22T09:39:36.479Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58842","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/A3lrPufimLlSmCGlhM2J","createTime":{"seconds":"1666431385","nanos":868236000},"updateTime":{"seconds":"1666431385","nanos":868236000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.479Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58843","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/rB0gpGkdyx694ITvHZeK","createTime":{"seconds":"1666431386","nanos":1925000},"updateTime":{"seconds":"1666431386","nanos":1925000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.479Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58844","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/RqXvAQGiYojGgKiPYQ3s","createTime":{"seconds":"1666431386","nanos":23856000},"updateTime":{"seconds":"1666431386","nanos":23856000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
<<snip document fetches that increment by 1>>
Firestore (4.15.1) 2022-10-22T09:39:36.483Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58908","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/tgEr50ODWDGyJ1Q85NPg","createTime":{"seconds":"1666431385","nanos":958878000},"updateTime":{"seconds":"1666431385","nanos":958878000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.483Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58909","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/tWkTMbivyeZRSr4cCWaE","createTime":{"seconds":"1666431385","nanos":814137000},"updateTime":{"seconds":"1666431385","nanos":814137000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:39:36.483Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"58910","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/MgxnJZFIhbuKJDAsm9vW","createTime":{"seconds":"1666431385","nanos":92463000},"updateTime":{"seconds":"1666431385","nanos":92463000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
<<snip document fetches that increment by 1>>
Firestore (4.15.1) 2022-10-22T09:41:36.477Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"99997","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/m8qzAqXGFALlklyVWaJE","createTime":{"seconds":"1666431403","nanos":465775000},"updateTime":{"seconds":"1666431403","nanos":465775000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:41:36.477Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"99998","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/YuBZR39BEhC7Uxc4AYTd","createTime":{"seconds":"1666431403","nanos":88294000},"updateTime":{"seconds":"1666431403","nanos":88294000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:41:36.477Z hGIr6 [Firestore.requestStream]: Received response: {"document":{"fields":{"foo":{"integerValue":"99999","valueType":"integerValue"}},"name":"projects/my-project/databases/(default)/documents/docs/G8Ooox3mwKBoGm0uJy2k","createTime":{"seconds":"1666431402","nanos":27423000},"updateTime":{"seconds":"1666431402","nanos":27423000}},"transaction":{"type":"Buffer","data":[]},"readTime":{"seconds":"1666431403","nanos":703161000},"skippedResults":0}
Firestore (4.15.1) 2022-10-22T09:41:36.477Z hGIr6 [Firestore._initializeStream]: Received stream end
done counting at 11:41:36
At the end of the script I print all the numbers we've received from the stream and you can see the stream resets back to 58841 after already having received 58855:
58840,
58841,
58842,
58843,
58844,
58845,
58846,
58847,
58848,
58849,
58850,
58851,
58852,
58853,
58854,
58855,
58841,
58842,
58843,
58844,
58845,
58846,
58847,
58848,
58849,
58850,
58851,
58852,
58853,
58854,
58855,
58856,
58857,
58858,
58859,
58860,
As a workaround we'll be wrapping the stream with a stream of our own to keep a sliding window of the last 16 document-id's so we can remove the duplicates.
Apologies I couldn't create a 100% reproducible example or a failing unit test. Hopefully there is enough information in this bug report for you to create a failing unit test.
Environment details
@google-cloud/firestoreversion: 4.15.1In production (Cloud Run) we are suffering from an intermittent issue where we receive some documents twice from
query.stream(). In our production code this reproduces almost 100% of the time and I've been trying to get a locally running example. Unfortunately I cannot get it to reproduce as frequently, but it does fail sometimes.Logging indicates we suffer from an error:
Received stream error: Error: 14 UNAVAILABLE: The datastore operation timed out, or the data was temporarily unavailable.The implementation at
nodejs-firestore/dev/src/reference.ts
Line 2347 in 50747ad
lastReceivedDocumentbut this sometimes seems to restart at a point that re-emits 15 documents from the stream that have already been emitted.I guess there is some buffering going on between the different streams that are set up. According to https://nodejs.org/api/stream.html#buffering object streams have a default of 16 buffered objects and we consistently see 15 re-remitted documents. So it seems some documents are already in some buffer without
lastReceivedDocumentknowing about it.It also appears that there might be multiple stream with 16 buffered elements at play here. After receiving document
58855the stream resets to58841but the actual firestore error from the backend was after receiving58902which is even further along in the query.My guess is that the root cause is error handler on the
backendStreamatnodejs-firestore/dev/src/reference.ts
Line 2335 in 50747ad
lastReceivedDocument, but could it be that there are still documents buffered between thebackendStreamand the transformer that builds them into documents and keeps track of thelastReceivedDocument. If so, shouldn't these first be flushed to the transformer to emit them and increase thelastReceivedDocumentbefore making a next attempt?The example below sometimes reproduces this error locally:
The full logfile is 120MB and a bit much for a github issue attachment. Below is the interesting part where you can see the documents being fetched, the error and then some of the old documents being fetched again:
At the end of the script I print all the numbers we've received from the stream and you can see the stream resets back to
58841after already having received58855:And the script ends with an assertion error:
As a workaround we'll be wrapping the stream with a stream of our own to keep a sliding window of the last 16 document-id's so we can remove the duplicates.
Apologies I couldn't create a 100% reproducible example or a failing unit test. Hopefully there is enough information in this bug report for you to create a failing unit test.