Repository navigation
Unhandled promises in Topic.flush and PubSub.close prevent proper shutdown #1463
Description
Activity
- addedapi: pubsubIssues related to the googleapis/nodejs-pubsub API.Issues related to the googleapis/nodejs-pubsub API.
on Jan 15, 2022 - changed the title
[-]Dangling promises in Topic.flush and PubSub.close prevent proper shutdown[/-][+]Unhandled promises in Topic.flush and PubSub.close prevent proper shutdown[/+]on Jan 15, 2022 After a little more inspection of the
Topic.flushcode path, I think the problem with unhandled promises is actually more wide-spread. Take a look at the following line of code fromPublisher.flush:nodejs-pubsub/src/publisher/index.ts
Lines 110 to 124 in 38fba8b
flush(callback?: EmptyCallback): Promise<void> | void { const definedCallback = callback ? callback : () => {}; const publishes = [promisify(this.queue.publish).bind(this.queue)()]; Array.from(this.orderedQueues.values()).forEach(q => publishes.push(promisify(q.publish).bind(q)()) ); const allPublishes = Promise.all(publishes); allPublishes .then(() => { definedCallback(null); }) .catch(definedCallback); } In line 113 the internal
Queue.publishmethod is called to publish the remaining messages. Thecallbackfrom line 110 isn't passed down intoQueue.publish. InsteadPromise.allis used to wait for the queue to publish. But theQueue.publishmethod itself isvoid; it is not returning aPromisethat can be awaited.nodejs-pubsub/src/publisher/message-queues.ts
Lines 162 to 173 in 38fba8b
publish(callback?: PublishDone): void { const {messages, callbacks} = this.batch; this.batch = new MessageBatch(this.batchOptions); if (this.pending) { clearTimeout(this.pending); delete this.pending; } this._publish(messages, callbacks, callback); } With this, it seems currently impossible to reliably await the complete publication of all message with this library, no?
Reacted by James Carnegie- addedtriage meI really want to be triaged.I really want to be triaged.
on Jan 16, 2022 @cdupuis Thanks for the report. That does look wrong at first glance, but I wonder if this code was relying on
promisify(), and I missed updating it or something.- addedpriority: p2Moderately-important priority. Fix may not be included in next release.Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.and removedtriage meI really want to be triaged.I really want to be triaged.
on Jan 17, 2022 I'm moving this to our internal backlog to look at along with other unhandled promise and graceful shutdown issues.
Re-opening this upon request from TSEs.
- added🚨This issue needs some love.This issue needs some love.and removed🚨This issue needs some love.This issue needs some love.
on Jun 26, 2022 This got some changes from the exactly once delivery work, and it looks like the current unit tests should cover it, so I think this is finished. Please comment if you're still having the issue.
- added a commit that references this issue
on Nov 12, 2024
Both methods
Topic.flushandPubSub.closeindicate that it is ok to call them with no parameter andawaittheir completion. Unfortunately when passing no callback, the function internals don't properlyawaitand instead have unhandled promises which can in certain cases lead to message not being sent correctly.This could be a reason to the recently observed increase in
Total timeout of API google.pubsub.v1.Publisher exceeded 60000 milliseconds before any response was received.errors on Google Cloud Functions and Cloud Run because those runtime instances assumingly switch to idle before all messages have been send.Take a look at
Topic.flush:nodejs-pubsub/src/topic.ts
Lines 193 to 199 in 38fba8b
The call to
this.publisher.flush(callback!);is not awaited nor returned so there is no way for the caller ofTopic.flushtoawaitthe internal Promise completion without passing acallback.Similar issue exists in
PubSub.close.