未使用await调用抛异常的async函数致Nest.js应用无响应
Nest.js中未await异步函数抛出异常导致服务无响应的解决方案
问题背景
当async函数未使用await调用且抛出异常时,Nest.js应用会进入不再响应请求但进程未终止的状态。部分场景下我们无需等待异步函数完成就返回响应,但多数情况是意外遗漏了await,这会导致服务器失效,排查难度大。
复现代码
app.controller.ts
import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; @Controller() export class AppController { constructor(private readonly appService: AppService) {} @Get() getHello(): string { return this.appService.getHello(); } @Get('/crash') public async crash(): Promise<void> { await this.appService.crash(); } }
app.service.ts
import { Injectable } from '@nestjs/common'; const sleep = async (ms: number): Promise<void> => { return new Promise((resolve) => { setTimeout(resolve, ms); }); }; const functionThatThrows = async (): Promise<void> => { await sleep(2000); throw new Error('this will crash the app'); }; @Injectable() export class AppService { getHello(): string { return 'Hello World!'; } public async crash(): Promise<void> { console.log('crashing the app in 3 seconds...'); await sleep(1000); functionThatThrows(); // async function called without await } }
复现步骤
- 首次调用
curl http://localhost:3000/crash,接口正常返回; - 再次调用该接口时,服务器无响应,提示:
curl: (7) 无法连接到localhost的3000端口,连接耗时5毫秒后失败:拒绝连接
解决方案
1. 全局捕获未处理的Promise拒绝
在Nest.js入口文件(main.ts)中添加Node.js的unhandledRejection事件监听,捕获所有未被处理的Promise异常,避免服务陷入无响应状态:
async function bootstrap() { const app = await NestFactory.create(AppModule); await app.listen(3000); // 捕获未处理的Promise拒绝 process.on('unhandledRejection', (reason, promise) => { console.error('未处理的Promise异常:', reason); // 可根据业务需求添加日志上报、服务重启逻辑 }); } bootstrap();
默认情况下,未处理的Promise拒绝会导致Node.js进程状态异常,监听该事件后可以统一处理这类异常,至少保证服务能继续响应后续请求。
2. 手动处理无await异步函数的异常
如果是故意不等待异步函数完成,必须手动捕获其异常,避免未捕获的Promise拒绝:
// 在app.service.ts中修改调用逻辑 functionThatThrows().catch(err => { console.error('异步操作异常:', err); // 可添加日志、告警等处理 });
3. 开发阶段代码检查(从根源避免)
使用ESLint规则@typescript-eslint/no-floating-promises,该规则会检测所有未被处理的Promise(即没有await、没有返回、没有.catch的异步函数调用),在开发阶段就发现遗漏await的问题。
配置方式:在ESLint配置文件中添加:
{ "rules": { "@typescript-eslint/no-floating-promises": "error" } }
开启后,代码中未处理的Promise调用会直接抛出ESLint错误,强制开发者处理这类异步操作。
内容的提问来源于stack exchange,提问作者Ambrose Krapacs
相关产品推荐
相关产品推荐

