CDK API Gateway Lambda 在增加超时时间后仍然超时

问题描述 投票:0回答:1

在从服务配额请求增加配额后,我已将 API 网关和 Lambda 函数的超时持续时间增加到 60 秒。参考:https://aws.amazon.com/about-aws/whats-new/2024/06/amazon-api-gateway-integration-timeout-limit-29-seconds/

但我现在仍然收到 504 错误。

我还检查了 lambda 日志,函数在 40 秒内完成。

我如何诊断问题所在?

该功能应该可以正常运行,没有任何错误。

编辑:

这是堆栈文件:

import { CfnOutput, Duration, Stack, StackProps } from "aws-cdk-lib";
import * as apigateway from "aws-cdk-lib/aws-apigateway";
import * as lambda from "aws-cdk-lib/aws-lambda";
import { Construct } from "constructs";

export class HelloAwsCdkStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // Defines AWS API Gateway
    const helloGateway = new apigateway.RestApi(this, "HelloGateway");

    // Defines AWS Lambda
    const helloLambda = new lambda.Function(this, "HelloHandler", {
      runtime: lambda.Runtime.NODEJS_16_X, // execution environment
      code: lambda.Code.fromAsset("lambda"), // code loaded from "lambda" directory.
      handler: "hello.handler", // file is "hello", function is "handler"
      timeout: Duration.seconds(90),
    });

    const helloLambdaIntegration = new apigateway.LambdaIntegration(
      helloLambda,
      {
        timeout: Duration.seconds(90),
      }
    );

    const helloResource = helloGateway.root.addResource("graphql");

    ["GET", "POST"].forEach((method) => {
      helloResource.addMethod(method, helloLambdaIntegration, {
        authorizationType: apigateway.AuthorizationType.NONE,
      });
    });

    // Defines the function url for the AWS Lambda
    const helloLambdaUrl = helloLambda.addFunctionUrl({
      authType: lambda.FunctionUrlAuthType.NONE,
    });

    // print the function url after deployment
    new CfnOutput(this, "FunctionUrl", { value: helloLambdaUrl.url });
  }
}

这是我的 lambda 函数文件:

exports.handler = async (event) => {
  console.log("DEBUG BEFORE SLEEP");
  await new Promise((r) => setTimeout(r, 60000));
  console.log("DEBUG AFTER SLEEP");

  return {
    statusCode: 200,
    body: JSON.stringify({ message: "Hello world" }),
  };
};

如您所见,网关和 Lambda 超时为 90 秒,函数中等待 60 秒,但 60 秒后我仍然在邮递员中收到此错误:

邮差错误

这些是 CloudWatch 日志:

CloudWatch 日志

注意:

需要注意的一件事是,我的生产环境中的 lambda 函数中有一个 Express 服务器,但我尝试使用 https://www.npmjs.com/package/connect-timeout 来增加超时,但它仍然得到30秒后退出。

更新:

我已经更新了堆栈文件如下,因为我在函数文件中有 Apollo GraphQL Server。

import { CfnOutput, Duration, Stack, StackProps } from "aws-cdk-lib";
import * as apigateway from "aws-cdk-lib/aws-apigateway";
import * as lambda from "aws-cdk-lib/aws-lambda";
import { Construct } from "constructs";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";

export class HelloAwsCdkStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // Defines AWS API Gateway
    const helloGateway = new apigateway.RestApi(this, "HelloGateway");

    // Defines AWS Lambda Layer
    const depsLayer = new lambda.LayerVersion(this, "NodeDependencies", {
      code: lambda.Code.fromAsset("layer"),
      compatibleRuntimes: [lambda.Runtime.NODEJS_16_X],
    });

    // Defines AWS Lambda
    const helloLambda = new NodejsFunction(this, "HelloHandler", {
      runtime: lambda.Runtime.NODEJS_16_X, // execution environment
      code: lambda.Code.fromAsset("lambda"), // code loaded from "lambda" directory.
      handler: "hello.handler", // file is "hello", function is "handler"
      timeout: Duration.seconds(90),
      layers: [depsLayer],
      bundling: {
        externalModules: [
          "apollo-server-core",
          "apollo-server-lambda",
          "connect-timeout",
          "express",
          "graphql",
        ],
      },
    });

    const helloLambdaIntegration = new apigateway.LambdaIntegration(
      helloLambda,
      {
        timeout: Duration.seconds(90),
      }
    );

    const helloResource = helloGateway.root.addResource("graphql");

    ["GET", "POST"].forEach((method) => {
      helloResource.addMethod(method, helloLambdaIntegration, {
        authorizationType: apigateway.AuthorizationType.NONE,
      });
    });

    // Defines the function url for the AWS Lambda
    const helloLambdaUrl = helloLambda.addFunctionUrl({
      authType: lambda.FunctionUrlAuthType.NONE,
    });

    // print the function url after deployment
    new CfnOutput(this, "FunctionUrl", { value: helloLambdaUrl.url });
  }
}

这是更新后的 lambda 函数文件:

const express = require("express");
const timeout = require("connect-timeout");
const { ApolloServer, gql } = require("apollo-server-lambda");
const {
  ApolloServerPluginLandingPageLocalDefault,
} = require("apollo-server-core");

// Construct a schema, using GraphQL schema language
const typeDefs = gql`
  type Query {
    hello: String
  }
`;

// Provide resolver functions for your schema fields
const resolvers = {
  Query: {
    hello: async () => {
      await new Promise(r => setTimeout(r, 40000));
      return "Hello world!";
    },
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
  csrfPrevention: true,
  cache: "bounded",
  context: ({ event, context, express }) => ({
    headers: event.headers,
    functionName: context.functionName,
    event,
    context,
    expressRequest: express.req,
  }),
  plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
});

function haltOnTimedout(req, res, next) {
  if (!req.timedout) next();
}

exports.handler = server.createHandler({
  expressAppFromMiddleware: (middleware) => {
    const app = express();
    app.use(timeout("90s"));
    app.use(middleware);
    app.use(haltOnTimedout);
    return app;
  },
});

如您所见,我添加了与 lambda 和 API 网关相同的 90 秒超时中间件,但

hello
查询只有 40 秒超时。

我使用 lambda 函数 URL 和 API 网关端点进行了测试。只有前者有效,而后者在 30 秒后抛出以下错误:

"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<HTML><HEAD><META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=iso-8859-1\">\n<TITLE>ERROR: The request could not be satisfied</TITLE>\n</HEAD><BODY>\n<H1>504 ERROR</H1>\n<H2>The request could not be satisfied.</H2>\n<HR noshade size=\"1px\">\nCloudFront attempted to establish a connection with the origin, but either the attempt failed or the origin closed the connection.\nWe can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.\n<BR clear=\"all\">\nIf you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.\n<BR clear=\"all\">\n<HR noshade size=\"1px\">\n<PRE>\nGenerated by cloudfront (CloudFront)\nRequest ID: IgaxrsYnf_duw7CJYtivWNAOeV4YyMLR7YOridwIng9H0vnjXtir1w==\n</PRE>\n<ADDRESS>\n</ADDRESS>\n</BODY></HTML>"

我必须使用 API 网关,因为我的生产环境是一个巨大的现有代码库,我不想更新它。

amazon-web-services aws-lambda aws-api-gateway aws-cdk
1个回答
0
投票

确保不要使用端点的边缘类型。根据文档,仅对区域和私有 Rest API 启用超时增加:

https://aws.amazon.com/about-aws/whats-new/2024/06/amazon-api-gateway-integration-timeout-limit-29-seconds/

© www.soinside.com 2019 - 2024. All rights reserved.