Serverless-offline运行NestJS本地后端频繁出现Lambda 504超时求助
使用serverless-offline插件本地运行NestJS后端,服务有时能正常运行,但发起任意请求(GET/POST均可)后,终端频繁出现**「× [504] - Lambda timeout」**错误。完整错误信息如下:
{"errorMessage":"[504] - Lambda timeout.","errorType":"LambdaTimeoutError","stackTrace":["Error: [504] - Lambda timeout.","at #timeoutAndTerminate (file:///C:/Users/z0044vnt/Desktop/diplomka/application-compliance-suite-monorepo/node_modules/serverless-offline/src/lambda/LambdaFunction.js:283:11)","at async LambdaFunction.runHandler (file:///C:/Users/z0044vnt/Desktop/diplomka/application-compliance-suite-monorepo/node_modules/serverless-offline/src/lambda/LambdaFunction.js:305:16)","at async file:///C:/Users/z0044vnt/Desktop/diplomka/application-compliance-suite-monorepo/node_modules/serverless-offline/src/events/http/HttpServer.js:602:18)","at async exports.Manager.execute (C:\Users\z0044vnt\Desktop\diplomka\application-compliance-suite-monorepo\node_modules\@hapi\hapi\lib\toolkit.js:60:28)","at async internals.handler (C:\Users\z0044vnt\Desktop\diplomka\application-compliance-suite-monorepo\node_modules\@hapi\hapi\lib\handler.js:46:20)","at async exports.execute (C:\Users\z0044vnt\Desktop\diplomka\application-compliance-suite-monorepo\node_modules\@hapi\hapi\lib\handler.js:31:20)","at async Request._lifecycle (C:\Users\z0044vnt\Desktop\diplomka\application-compliance-suite-monorepo\node_modules\@hapi\hapi\lib\request.js:370:32)"]}
此时NestJS应用甚至无法启动,Lambda已设置29秒超时,但实际远早于该时间就触发超时。本地服务器启动后所有请求均超时,执行命令sls offline --stage local --ignoreJWTSignature --noAuth后的终端输出:
npm run be:local > application-compliance-suite-monorepo@0.0.0 be:local > nx run backend:serve:local > nx run backend:serve:local Starting Offline at stage local (eu-central-1) No errors found. Offline [http for lambda] listening on http://localhost:3002 Function names exposed for local invocation by aws-sdk: * main: application-compliance-suite-backend-local-main │ │ │ ANY | http://localhost:3000/{proxy*} │ │ POST | http://localhost:3000/2015-03-31/functions/main/invocations │ │ GET | http://localhost:3000/swagger │ │ POST | http://localhost:3000/2015-03-31/functions/main/invocations │ │ GET | http://localhost:3000/swagger/{proxy*} │ │ POST | http://localhost:3000/2015-03-31/functions/main/invocations │ │ OPTIONS | http://localhost:3000/{proxy*} │ │ POST | http://localhost:3000/2015-03-31/functions/main/invocations │ │ GET | http://localhost:3000/local/swagger │ │ POST | http://localhost:3000/2015-03-31/functions/main/invocations │ │ GET | http://localhost:3000/local/swagger/{proxy*} │ │ POST | http://localhost:3000/2015-03-31/functions/main/invocations │ │ │ └───────────────────────────────────────────────────────────────────────────┘ Server ready: http://localhost:3000 🚀 GET /local/swagger (λ: main) × [504] - Lambda timeout. ANY /favicon.ico (λ: main) × [504] - Lambda timeout.
serverless.yml中的Lambda配置
functions: main: handler: src/main.handler memorySize: 256 timeout: 29 role: !GetAtt MainLambdaFunctionIAMRole.Arn vpc: ${file(serverless/sls-mappings.yml):stageMap.${self:provider.stage}.vpc} layers: - !Ref DependenciesLambdaLayer environment: STAGE: ${self:provider.stage} NO_COLOR: true REGION: ${self:custom.environmentVariables.${self:provider.stage}.region} DB_SECRET: ${self:custom.environmentVariables.${self:provider.stage}.dbSecret} events: - httpApi: # ApiGatewayV2 method: any path: /{proxy+} authorizer: name: customAuthorizer - httpApi: # Escape swagger method: get path: /swagger - httpApi: # Escape swagger method: get path: /swagger/{proxy*} - httpApi: # escaping the OPTIONS call method: options path: /{proxy+} - httpApi: # Escape swagger base url staged method: get path: /${self:provider.stage}/swagger - httpApi: # Escape swagger staged method: get path: /${self:provider.stage}/swagger/{proxy*}
package.json依赖配置
{ "name": "application-compliance-suite-monorepo", "version": "0.0.0", "license": "MIT", "scripts": { "nx": "nx", "be:local": "nx run backend:serve:local", "fe:local": "nx run frontend:serve:local" }, "private": true, "devDependencies": { "@angular-devkit/build-angular": "16.0.0", "@angular-eslint/eslint-plugin": "16.0.1", "@angular-eslint/eslint-plugin-template": "16.0.1", "@angular-eslint/template-parser": "16.0.1", "@angular/cli": "16.0.0", "@angular/compiler-cli": "16.0.0", "@angular/language-service": "16.0.0", "@nestjs/testing": "9.1.1", "@ngxs/devtools-plugin": "^3.8.1", "@ngxs/logger-plugin": "^3.8.1", "@nx/angular": "16.1.4", "@nx/cypress": "16.1.4", "@nx/esbuild": "16.1.4", "@nx/eslint-plugin": "16.1.4", "@nx/jest": "16.1.4", "@nx/js": "16.1.4", "@nx/linter": "16.1.4", "@nx/nest": "16.1.4", "@nx/node": "16.1.4", "@nx/workspace": "16.1.4", "@types/aws-lambda": "^8.10.110", "@types/jest": "^28.1.1", "@types/node": "18.7.1", "@types/node-rsa": "^1.1.1", "@types/passport-jwt": "^3.0.6", "@types/uuid": "^9.0.0", "@typescript-eslint/eslint-plugin": "5.58.0", "@typescript-eslint/parser": "5.58.0", "aws-cdk": "^2.62.0", "aws-cdk-lib": "^2.62.0", "constructs": "^10.1.231", "copy-webpack-plugin": "^11.0.0", "cypress": "^12.2.0", "esbuild": "0.17.17", "eslint": "~8.15.0", "eslint-config-prettier": "8.1.0", "eslint-plugin-cypress": "^2.10.3", "eslint-plugin-prettier": "^4.2.1", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", "jest-preset-angular": "13.1.0", "ng-packagr": "^16.0.1", "ngx-translate-testing": "^6.1.0", "nx": "16.1.4", "postcss": "^8.4.5", "postcss-import": "~14.1.0", "postcss-preset-env": "~7.5.0", "postcss-url": "~10.1.3", "prettier": "^2.6.2", "serverless": "^3.26.0", "serverless-offline": "^12.0.4", "serverless-plugin-reducer": "^4.0.1", "serverless-webpack": "^5.11.0", "ts-jest": "29.1.0", "ts-node": "10.9.1", "typescript": "5.0.4" }, "dependencies": { "@angular/animations": "16.0.0", "@angular/cdk": "16.0.0", "@angular/common": "16.0.0", "@angular/compiler": "16.0.0", "@angular/core": "16.0.0", "@angular/forms": "16.0.0", "@angular/material": "16.0.0", "@angular/platform-browser": "16.0.0", "@angular/platform-browser-dynamic": "16.0.0", "@angular/router": "16.0.0", "@automapper/classes": "^8.7.7", "@automapper/core": "^8.7.7", "@automapper/nestjs": "^8.7.7", "@automapper/types": "^6.3.1", "@aws-sdk/client-secrets-manager": "^3.264.0", "@aws-sdk/client-sqs": "^3.272.0", "@fastify/aws-lambda": "^3.0.0", "@fastify/static": "^6.10.2", "@fastify/swagger": "^8.3.1", "@nestjs/common": "9.1.1", "@nestjs/config": "^2.3.0", "@nestjs/core": "9.1.1", "@nestjs/jwt": "^10.0.0", "@nestjs/passport": "^9.0.0", "@nestjs/platform-fastify": "^9.2.0", "@nestjs/schematics": "9.1.0", "@nestjs/swagger": "6.3.0", "@nestjs/typeorm": "^9.0.1", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", "@ngxs/store": "^3.8.1", "angular-auth-oidc-client": "^15.0.3", "axios": "^1.2.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "css-vars-ponyfill": "^2.4.8", "node-rsa": "^1.1.1", "passport": "^0.6.0", "passport-custom": "^1.1.1", "pg": "^8.11.0", "reflect-metadata": "^0.1.13", "rxjs": "~7.5.0", "tslib": "^2.5.0", "typeorm": "^0.3.16", "zone.js": "^0.13.0" } }
运行环境:Windows 10、Node 18.16.0,本地资源占用(CPU、内存等)正常。
1. 本地VPC配置冲突
serverless.yml中为local阶段配置了VPC,但本地环境没有对应的VPC网络,导致Lambda进程无法正常初始化,进而触发超时。
解决办法
在serverless.yml中针对local阶段移除VPC配置:
- 修改
vpc字段为条件判断,仅在非local阶段启用:
vpc: ${file(serverless/sls-mappings.yml):stageMap.${self:provider.stage}.vpc, ""}
或者直接在local环境的配置映射文件中,将vpc值设为空。
2. 依赖版本不兼容
当前使用的serverless-offline@12.0.4与serverless@3.26.0、NestJS@9.x存在兼容性问题,导致Lambda函数执行时出现阻塞。
解决办法
- 降级serverless-offline到稳定兼容版本,比如
^11.5.0:
npm uninstall serverless-offline npm install serverless-offline@11.5.0 --save-dev
- 或者升级serverless到最新稳定版,确保与serverless-offline版本匹配。
3. 数据库连接阻塞
local阶段的DB_SECRET指向的数据库无法访问,NestJS启动时卡在数据库连接环节,导致Lambda超时。
解决办法
- 检查local阶段的数据库配置,确保本地能正常连接到目标数据库;
- 若本地不需要数据库,临时注释NestJS中TypeORM模块的初始化代码,或者为local阶段配置本地测试数据库(如SQLite)。
4. NestJS启动逻辑阻塞
NestJS应用在启动时的异步操作(如配置加载、第三方服务连接)未正确处理,导致Lambda进程无法完成初始化。
解决办法
- 在NestJS的
main.ts中,确保bootstrap()函数正确处理异步操作并捕获错误:
async function bootstrap() { try { const app = await NestFactory.create(AppModule); // 其他配置逻辑 await app.init(); } catch (error) { console.error('NestJS启动失败:', error); process.exit(1); } } bootstrap();
- 检查自定义守卫、拦截器或中间件,排查是否存在未正确处理的异步阻塞逻辑。
5. Windows系统路径/权限问题
Windows系统的文件路径格式可能与serverless-offline预期不符,或者进程没有足够权限读取文件。
解决办法
- 确保项目路径中无中文、空格或特殊字符;
- 以管理员身份运行终端,重新启动服务;
- 清理依赖后重新安装:
rm -rf node_modules package-lock.json npm install
内容的提问来源于stack exchange,提问作者hawran

