There seems to be an issue with .end being called when StreamConnection#close is called on an already closed stream.
It only seems to happen when the stream closes after it's been ABORTED (because the underlying system has closed the stream because it's been inactive for more than 600s), and then to clean up .close is called (on the JSONWriter for example).
Error when the stream is closed for inactivity:
stream_connection: connection closed | Error: 10 ABORTED: Closing the stream because it has been inactive for 600 seconds. Entity: projects/bookcreator-dev/datasets/custom_analytics/tables/events/streams/_default
at callErrorFromStatus (/app/node_modules/@grpc/grpc-js/build/src/call.js:32:19)
at Object.onReceiveStatus (/app/node_modules/@grpc/grpc-js/build/src/client.js:421:73)
at Object.onReceiveStatus (/app/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:324:181)
at /app/node_modules/@grpc/grpc-js/build/src/resolving-call.js:135:78
at processTicksAndRejections (internal/process/task_queues.js:77:11)
for call at
at ServiceClientImpl.makeBidiStreamRequest (/app/node_modules/@grpc/grpc-js/build/src/client.js:405:32)
at ServiceClientImpl.<anonymous> (/app/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19)
at /app/node_modules/@google-cloud/bigquery-storage/build/src/v1/big_query_write_client.js:220:29
at /app/node_modules/google-gax/build/src/streamingCalls/streamingApiCaller.js:46:28
at /app/node_modules/google-gax/build/src/normalCalls/timeout.js:44:16
at StreamProxy.setStream (/app/node_modules/google-gax/build/src/streamingCalls/streaming.js:248:24)
at StreamingApiCaller.call (/app/node_modules/google-gax/build/src/streamingCalls/streamingApiCaller.js:54:16)
at /app/node_modules/google-gax/build/src/createApiCall.js:112:30
at processTicksAndRejections (internal/process/task_queues.js:95:5) {
code: 10,
details: 'Closing the stream because it has been inactive for 600 seconds. Entity: projects/bookcreator-dev/datasets/custom_analytics/tables/events/streams/_default',
metadata: Metadata {
internalRepr: Map(1) { 'content-disposition' => [Array] },
options: {}
}
}
Then when calling .close:
stream_connection: on error | NodeError: Cannot call write after a stream was destroyed
at doWrite (/app/node_modules/readable-stream/lib/_stream_writable.js:409:38)
at writeOrBuffer (/app/node_modules/readable-stream/lib/_stream_writable.js:398:5)
at StreamProxy.Writable.write (/app/node_modules/readable-stream/lib/_stream_writable.js:307:11)
at StreamProxy.Duplexify.end (/app/node_modules/duplexify/index.js:234:41)
at StreamConnection.close (/app/node_modules/@google-cloud/bigquery-storage/build/src/managedwriter/stream_connection.js:298:26)
at Writer.close (/app/node_modules/@google-cloud/bigquery-storage/build/src/managedwriter/writer.js:113:32)
at JSONWriter.close (/app/node_modules/@google-cloud/bigquery-storage/build/src/managedwriter/json_writer.js:97:22)
at shutdown (/app/src/routes/events-insert.js:78:26)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async process.<anonymous> (/app/src/index.js:85:4)
To reproduce, open a connection to the default write stream and send some data using a JSONWriter. Then wait till the ABORTED error occurs and then call .close on the writer.
In StreamConnection#close, does #isConnectionClosed just need to be checked, instead of !this._connection?
There seems to be an issue with
.endbeing called whenStreamConnection#closeis called on an already closed stream.It only seems to happen when the stream closes after it's been
ABORTED(because the underlying system has closed the stream because it's been inactive for more than 600s), and then to clean up.closeis called (on theJSONWriterfor example).Error when the stream is closed for inactivity:
Then when calling
.close:To reproduce, open a connection to the default write stream and send some data using a
JSONWriter. Then wait till theABORTEDerror occurs and then call.closeon the writer.In
StreamConnection#close, does#isConnectionClosedjust need to be checked, instead of!this._connection?