Heroku上Nest.Js应用间歇性H12请求超时崩溃问题排查求助
排查Heroku上Nest.js应用间歇性H12超时的方案
一、深度调试策略
- 追踪请求全链路耗时:在Nest.js全局拦截器中添加全请求生命周期日志,记录每个请求的
开始时间、路由、结束时间、总耗时,同时捕获所有异步操作的等待时长(比如数据库连接池获取、第三方API调用的等待,这类隐性耗时不会被单函数监控捕获)。示例代码:
@Injectable() export class RequestTimingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const request = context.switchToHttp().getRequest(); const startTime = Date.now(); const route = request.route?.path || request.url; return next.handle().pipe( tap(() => { const totalTime = Date.now() - startTime; console.log(`[REQUEST_TIMING] 路由: ${route}, 总耗时: ${totalTime}ms`); }), catchError(err => { const totalTime = Date.now() - startTime; console.error(`[REQUEST_ERROR] 路由: ${route}, 总耗时: ${totalTime}ms, 错误: ${err.message}`); throw err; }), ); } }
- 排查事件循环阻塞:Node.js事件循环阻塞是隐性超时的常见原因,即便单函数耗时正常,阻塞会导致后续请求排队超时。添加定期检测逻辑:
setInterval(() => { const start = process.hrtime(); setImmediate(() => { const diff = process.hrtime(start); const delay = diff[0] * 1e3 + diff[1] / 1e6; if (delay > 50) { // 阈值设为50ms,超过则记录异常 console.warn(`[EVENT_LOOP_BLOCKED] 延迟: ${delay}ms`); } }); }, 1000);
- 监控数据库连接池状态:单查询耗时正常不代表连接池无问题,偶尔连接池耗尽会导致请求等待获取连接,这个等待时长不会被单函数监控捕获。以TypeORM为例,添加连接池状态日志:
const connection = getConnection(); setInterval(() => { const pool = connection.driver.pool; console.log(`[DB_POOL] 活跃连接数: ${pool.activeConnections.length}, 等待队列长度: ${pool.waitingConnections.length}`); }, 30000);
二、增强监控方案
- 绑定Heroku请求ID:Heroku每个请求都会分配唯一的
X-Request-ID,在Nest.js中将该ID注入所有日志,把Heroku的H12错误日志和应用内日志关联,精准定位对应请求的全链路记录。 - 事件循环利用率监控:利用Node.js 14+支持的
eventLoopUtilization接口,记录事件循环利用率,一旦超过80%就标记异常,快速发现隐性阻塞。 - 捕获未处理Promise拒绝:未处理的Promise拒绝不会直接崩溃,但会导致事件循环异常,进而引发请求超时。添加全局捕获:
process.on('unhandledRejection', (reason, promise) => { console.error(`[UNHANDLED_REJECTION] Promise: ${promise}, 原因: ${reason}`); });
三、Heroku专属配置优化
- 调整Web Dyno参数:通过
heroku config:set WEB_CONCURRENCY=2调整并发数,避免单进程过载;启用Heroku的Preboot功能,减少部署时的请求中断,同时确保Nest.js实现优雅关闭逻辑。 - 分析Heroku路由日志:过滤Heroku的
router日志中的H12错误,查看connect、service字段,区分是路由层等待应用响应超时,还是应用内部处理超时。 - 切换容器部署:若当前使用buildpack部署,尝试改用容器部署,排除buildpack带来的环境差异,确保Node.js版本、依赖与本地完全一致。
内容的提问来源于stack exchange,提问作者Ali Mohammad
相关产品推荐
相关产品推荐

