Node.js 14 trở về trước: unhandled rejection chỉ print warning, process tiếp tục — silent failure nguy hiểm.
Node.js 15+: mặc định crash process với exit code 1 — breaking change.
Hierarchy xử lý đúng:
- try/catch trong async functions là chính,
.catch()chain cho fire-and-forget promises,process.on('unhandledRejection', (reason) => { logger.error('Unhandled rejection', reason); gracefulShutdown(1); })là safety net cuối — không phải cơ chế chính.process.on('uncaughtException', (err) => { logger.error(err); gracefulShutdown(1); })cho sync throws
Monitoring: gửi đến Sentry trước khi shutdown — Sentry.captureException(reason); await Sentry.flush(2000).
Graceful shutdown: stop accepting requests, wait for in-flight, close DB, exit.
Dùng ESLint rule @typescript-eslint/no-floating-promises để catch missing awaits lúc compile time — tốt hơn runtime detection.