You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
    Integration Request HTTP headers
  • 当前API网关集成类型并非异步调用要求的Lambda代理集成
    Integration Request type

问题根因与修复方案

核心问题

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配置片段:
    provider:
      lambdaHashingVersion: "20201221"
      name: aws
      runtime: nodejs14.x
      region: us-east-1
      apiGateway:
        minimumCompressionSize: 1024
        shouldStartNameWithService: true
    
    修正后的functions事件配置片段:
    functions:
      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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 10:57:54