无服务器Express lambda async调用不起作用

发布于 2025-02-04 05:03:12 字数 3843 浏览 5 评论 0 原文

我在lambda中有一个基本的无服务器Express应用程序,路由设置为 async true。我想与其他应用程序异步触发此路线,并希望它在后台运行,而不必等待响应。

我的完整无服务器

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的权限,我可以从同步调用中看到日志,但不能从异步调用中看到。

我的index.middyhandler

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"
      },
    })
  )

在调用此方法时,它立即正确返回200个响应。但是实际的代码永远不会运行,我在其中有一个数据库插入物,而且不会发生。在API网关中,我可以看到 X-AMZ-Invocation-type 标题已正确传递为 event 类型。

这不是代理集成,如异步调用所需

我在这里缺少什么?路由控制器是测试,代码非常简单,

 testAsync: async (req, res) => {
    console.log("In Test Async");  // Does not display in Cloudwatch
    try {
      const { value } = req.body;
      const resp = await updateTest(value);  // This just inserts an entry in the DB with value
      return res.send(resp);
    } catch (err) {
      return res.status(500).send(err);
    }
  },

我这里还有其他设置吗?我不是AWS专家,因此任何帮助都将不胜感激。谢谢!

I have a basic Serverless Express app in a lambda, with a route set to async true. I want to trigger this route asynchronously from a different application, and expect it to run in the background without having to wait for the response.

My full 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


Note: The role that deploys this app has permissions to read write to Cloudwatch, and I can see logs from the synchronous invocations, but not from async invocations.

My index.middyHandler

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"
      },
    })
  )

When I call this method, it correctly returns a 200 response immediately. But the actual code is never run, I have a DB insert in there, and it doesn't happen. In the API Gateway I can see the X-Amz-Invocation-Type header is correctly being passed as Event type.

Integration Request HTTP headers

It is not a proxy integration, as required for async invocation
Integration Request type

What am I missing here? The route controller is a test and the code is very simple

 testAsync: async (req, res) => {
    console.log("In Test Async");  // Does not display in Cloudwatch
    try {
      const { value } = req.body;
      const resp = await updateTest(value);  // This just inserts an entry in the DB with value
      return res.send(resp);
    } catch (err) {
      return res.status(500).send(err);
    }
  },

Is there any other setting I'm missing here? I'm not an AWS expert, so any help would be highly appreciated. Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文