Skip to content

Commit f0dc17e

Browse files
fix(api): handle NuQ AMQP shutdown closes (firecrawl#3654)
1 parent 0f46ef4 commit f0dc17e

1 file changed

Lines changed: 50 additions & 6 deletions

File tree

  • apps/api/src/services/worker

apps/api/src/services/worker/nuq.ts

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,42 @@ function normalizeOwnerId(ownerId: string | undefined | null): string | null {
6060
return uuidv5(ownerId, normalizedUUIDNamespace);
6161
}
6262

63+
function isExpectedAmqpCloseError(error: unknown): boolean {
64+
const message =
65+
error instanceof Error
66+
? error.message
67+
: error && typeof error === "object" && "message" in error
68+
? String(error.message)
69+
: typeof error === "string"
70+
? error
71+
: "";
72+
73+
return (
74+
message === "Connection closing" ||
75+
message === "Connection closed" ||
76+
message === "Channel closing" ||
77+
message === "Channel closed"
78+
);
79+
}
80+
81+
async function closeAmqpResource(
82+
close: () => Promise<unknown>,
83+
resource: string,
84+
) {
85+
try {
86+
await close();
87+
} catch (error) {
88+
if (isExpectedAmqpCloseError(error)) {
89+
logger.info(`NuQ ${resource} already closing during shutdown`, {
90+
module: "nuq/rabbitmq",
91+
});
92+
return;
93+
}
94+
95+
throw error;
96+
}
97+
}
98+
6399
// === Queue
64100

65101
class NuQ<JobData = any, JobReturnValue = any> {
@@ -318,7 +354,9 @@ class NuQ<JobData = any, JobReturnValue = any> {
318354

319355
channel.on("close", () => {
320356
logger.info("NuQ sender channel closed", { module: "nuq/rabbitmq" });
321-
connection.close().catch(() => {});
357+
if (!this.shuttingDown) {
358+
connection.close().catch(() => {});
359+
}
322360
this.sender = null;
323361
});
324362

@@ -1482,16 +1520,22 @@ class NuQ<JobData = any, JobReturnValue = any> {
14821520
await nl.client.query(`UNLISTEN "${this.queueName}";`);
14831521
await nl.client.end();
14841522
} else {
1485-
await nl.channel.cancel(nl.queue);
1486-
await nl.channel.close();
1487-
await nl.connection.close();
1523+
await closeAmqpResource(
1524+
() => nl.channel.cancel(nl.queue),
1525+
"listener channel consumer",
1526+
);
1527+
await closeAmqpResource(() => nl.channel.close(), "listener channel");
1528+
await closeAmqpResource(
1529+
() => nl.connection.close(),
1530+
"listener connection",
1531+
);
14881532
}
14891533
}
14901534
if (this.sender) {
14911535
const ns = this.sender;
14921536
this.sender = null;
1493-
await ns.channel.close();
1494-
await ns.connection.close();
1537+
await closeAmqpResource(() => ns.channel.close(), "sender channel");
1538+
await closeAmqpResource(() => ns.connection.close(), "sender connection");
14951539
}
14961540
}
14971541
}

0 commit comments

Comments
 (0)