diff --git a/src/instrumentation.ts b/src/instrumentation.ts index e0d3191..50bf09b 100644 --- a/src/instrumentation.ts +++ b/src/instrumentation.ts @@ -1,5 +1,19 @@ export async function register() { 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"); await ensureTelegramBotStarted(); diff --git a/src/lib/tickets/service.ts b/src/lib/tickets/service.ts index 13c95fc..0474d37 100644 --- a/src/lib/tickets/service.ts +++ b/src/lib/tickets/service.ts @@ -169,9 +169,15 @@ async function appendMessage(params: { // Fire-and-forget: push delivery is a best-effort side channel for // backgrounded/frozen tabs, not part of the message-creation contract — // 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") { - void notifyPushForCustomerMessage(dto, messageDto, params.ticketIsNew); + notifyPushForCustomerMessage(dto, messageDto, params.ticketIsNew).catch((err) => { + console.error("[push] notifyPushForCustomerMessage failed:", err); + }); } return { ticket: dto, message: messageDto };