Serverless Express Lambda async异步调用不生效问题排查
AWS Lambda部署Serverless Express异步路由不执行业务代码问题排查
问题场景
在AWS Lambda上部署基础Serverless Express应用,将指定POST路由配置为async: true,期望实现从其他应用异步触发该路由、任务后台运行、调用方无需等待响应的效果,但实际调用时接口立即返回200,路由内业务代码完全不执行,异步调用对应日志也无法在CloudWatch中查看。
现有配置说明
serverless.yml 完整配置
service: service-name useDotenv: true custom: serverless-offline: useChildProcesses: true webpack: webpackConfig: ./webpack.config.js packager: "yarn" includeModules: forceExclude: - aws-sdk prune: automatic: true includeLayers: true number: 3 envStage: staging: staging domainPrefix: staging: service.staging customDomain: domainName: ${self:custom.domainPrefix.${opt:stage}}.mydomain.com basePath: "" stage: ${self:custom.envStage.${opt:stage}} createRoute53Record: true plugins: - serverless-domain-manager - serverless-webpack - serverless-prune-plugin - serverless-offline provider: lambdaHashingVersion: "20201221" name: aws runtime: nodejs14.x region: us-east-1 apiGateway: minimumCompressionSize: 1024 iamRoleStatements: - Effect: Allow Action: ssm:Get* Resource: "arn:aws:ssm:*:*:parameter/myparams/*" - Effect: Allow Action: kms:Decrypt Resource: "*" functions: express: handler: src/index.middyHandler events: - http: path: / method: options - http: path: /{any+} # Catch all routes method: options - http: path: foo/{any+} method: get - http: path: foo/{any+} method: post async: true
注:部署应用的角色已配置CloudWatch读写权限,同步调用产生的日志可正常查看,仅异步调用日志缺失
Lambda 入口handler代码
import serverless from "serverless-http"; import express from "express"; import helmet from "helmet"; import bodyParser from "body-parser"; import cookieParser from "cookie-parser"; import middy from "@middy/core"; import ssm from "@middy/ssm"; import doNotWaitForEmptyEventLoop from "@middy/do-not-wait-for-empty-event-loop"; import cors from "cors"; import fooRoutes from "./routes/foo"; const app = express(); app.use( cors({ methods: "GET,HEAD,OPTIONS,POST", preflightContinue: false, credentials: true, origin: true, optionsSuccessStatus: 204, }) ); app.use(helmet({ contentSecurityPolicy: false, crossOriginEmbedderPolicy: false })); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(cookieParser()); app.get("/ping", (req, res) => { res.send("Pong!"); }); // Register routes app.use("/foo", fooRoutes); const handler = serverless(app); export const middyHandler = middy(handler) .use( doNotWaitForEmptyEventLoop({ runOnError: true, runOnAfter: true, runOnBefore: true, }) ) .use( ssm({ setToEnv: true, fetchData: { MY_KEYS: "ssm/path" }, }) )
测试路由代码
testAsync: async (req, res) => { console.log("In Test Async"); // 该日志不会在Cloudwatch中显示 try { const { value } = req.body; const resp = await updateTest(value); // 向数据库插入value对应记录 return res.send(resp); } catch (err) { return res.status(500).send(err); } },
已确认现象
- 调用异步配置的POST接口时立即返回200响应
- 路由内数据库插入操作从未生效
- API Gateway控制台已确认
X-Amz-Invocation-Type请求头正确传递,值为Event
- 当前API网关集成类型并非异步调用要求的Lambda代理集成

问题根因与修复方案
核心问题
Serverless Framework中HTTP事件的async: true配置仅对Lambda代理集成生效,当前配置下API Gateway没有自动启用代理集成,是所有异常的根源:
- 非代理集成模式下,就算手动在控制台配置了
X-Amz-Invocation-Type: Event请求头映射,API Gateway也不会按异步规则调用Lambda,请求甚至不会正确透传到Express路由层。这就是为什么看不到业务日志、数据库操作不执行——Lambda根本没有运行路由逻辑,API Gateway收到请求后直接返回了默认200响应。 - 同一路径
foo/{any+}下配置了GET、POST两个不同方法,还配置了顶层通配符的OPTIONS路由,多事件规则未显式指定代理集成时,Serverless框架生成API Gateway配置会自动fallback到非代理集成,和控制台看到的集成类型截图完全吻合。
修复步骤
- 强制全局启用Lambda代理集成:在
provider.apiGateway配置块下添加shouldStartNameWithService: true,同时给所有http事件显式加上integration: lambda-proxy声明,避免同路径多方法时集成类型被覆盖。
修正后的provider配置片段:
修正后的functions事件配置片段:provider: lambdaHashingVersion: "20201221" name: aws runtime: nodejs14.x region: us-east-1 apiGateway: minimumCompressionSize: 1024 shouldStartNameWithService: truefunctions: express: handler: src/index.middyHandler events: - http: path: / method: options integration: lambda-proxy - http: path: /{any+} method: options integration: lambda-proxy - http: path: foo/{any+} method: get integration: lambda-proxy - http: path: foo/{any+} method: post integration: lambda-proxy async: true - 删除handler中的
doNotWaitForEmptyEventLoop中间件:异步调用模式下Lambda触发后会立刻向API Gateway返回202响应,不需要手动控制事件循环等待逻辑,该中间件在异步场景下反而会打断handler正常执行流程。 - 清理旧资源后重新部署:先执行
sls remove删除之前生成的错误API Gateway、Lambda资源,再执行sls deploy重新全量部署,避免旧配置残留。
验证标准
部署完成后进入API Gateway控制台,确认对应POST路由的集成类型为「Lambda代理集成」。此时调用接口会返回202 Accepted状态码(之前返回200就是配置未生效的典型标志),等待1分钟左右即可在CloudWatch查到业务日志,数据库插入逻辑也会正常执行。
内容的提问来源于stack exchange,提问作者kvnam
相关产品推荐
相关产品推荐

