Fix server crashes from unhandled push-notification errors
Root cause of the regressions reported after the Web Push feature landed (chat messages not appearing until refresh, notifications stopping entirely — even in-page toast/sound, which has nothing to do with push): the fire-and-forget push call in appendMessage() had no .catch(). This app has no global unhandledRejection handler, and Node terminates the whole process on an unhandled rejection by default — so any error inside notifyPushForCustomerMessage() (e.g. the unguarded db.query.users.findMany() call, which can hit SQLITE_BUSY under concurrent load, something this exact codebase has already hit elsewhere) would crash the entire server on every customer message, not just fail that one push send. Docker's restart policy masked it as "weird flakiness" rather than an obvious crash loop. Two fixes: the push call now has a .catch() so a failure there can never escape as an unhandled rejection, and — as a general safety net, since this codebase had no equivalent to project-claude's uncaughtException/unhandledRejection handlers — instrumentation.ts now logs-and-continues on both, so a future bug in any other fire-and-forget path can't take the whole server down either. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012o9j9RezxbZVKQMrB7oRLY
This commit is contained in:
1 parent
b9a247c21c
commit
71c0689af9
2 files changed
+22
-2
No files matched your search
@@ -1,5 +1,19 @@
|
|||||||
export async function register() {
|
export async function register() {
|
||||||
if (process.env.NEXT_RUNTIME === "nodejs") {
|
if (process.env.NEXT_RUNTIME === "nodejs") {
|
||||||
|
// Node terminates the whole process on an unhandled promise rejection
|
||||||
|
// by default — one bug in any best-effort/fire-and-forget path (push
|
||||||
|
// notifications, a background job, ...) would otherwise take down every
|
||||||
|
// in-flight request, not just the one that triggered it. Log-and-continue
|
||||||
|
// is the right call here: anything that reaches this handler was already
|
||||||
|
// meant to be non-fatal (a real, must-not-fail error should be caught and
|
||||||
|
// handled at its own call site instead).
|
||||||
|
process.on("uncaughtException", (err) => {
|
||||||
|
console.error("[process] uncaughtException (ignored, server continues)", err);
|
||||||
|
});
|
||||||
|
process.on("unhandledRejection", (reason) => {
|
||||||
|
console.error("[process] unhandledRejection (ignored, server continues)", reason);
|
||||||
|
});
|
||||||
|
|
||||||
const { ensureTelegramBotStarted } = await import("@/lib/telegram/bot");
|
const { ensureTelegramBotStarted } = await import("@/lib/telegram/bot");
|
||||||
await ensureTelegramBotStarted();
|
await ensureTelegramBotStarted();
|
||||||
|
|
||||||
|
|||||||
@@ -169,9 +169,15 @@ async function appendMessage(params: {
|
|||||||
// Fire-and-forget: push delivery is a best-effort side channel for
|
// Fire-and-forget: push delivery is a best-effort side channel for
|
||||||
// backgrounded/frozen tabs, not part of the message-creation contract —
|
// backgrounded/frozen tabs, not part of the message-creation contract —
|
||||||
// callers (mail ingestion, the API routes) must not wait on or fail from
|
// callers (mail ingestion, the API routes) must not wait on or fail from
|
||||||
// a slow/unreachable push service.
|
// a slow/unreachable push service. The .catch() here is load-bearing:
|
||||||
|
// this app has no global unhandledRejection handler, so an uncaught
|
||||||
|
// rejection from this call would otherwise crash the whole Node process
|
||||||
|
// (Node terminates on unhandled rejections by default) — taking down
|
||||||
|
// every in-flight request, not just this one message.
|
||||||
if (params.authorType === "customer") {
|
if (params.authorType === "customer") {
|
||||||
void notifyPushForCustomerMessage(dto, messageDto, params.ticketIsNew);
|
notifyPushForCustomerMessage(dto, messageDto, params.ticketIsNew).catch((err) => {
|
||||||
|
console.error("[push] notifyPushForCustomerMessage failed:", err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ticket: dto, message: messageDto };
|
return { ticket: dto, message: messageDto };
|
||||||
|
|||||||
Reference in new issue
Block a user