当另一个(长时间运行的)Lambda 被调用时,AWS Lambda 超时

4

我正在使用链接多个Lambda函数的步骤函数。其中一个Lambda函数中我调用了另一个Lambda函数。这两个Lambda函数都设置了15分钟的超时时间。但是,在一些时间后,调用次级Lambda函数的主要Lambda函数超时了(而次级Lambda函数仍然愉快地继续工作)。

Error

com.amazonaws.SdkClientException
Cause

{"errorMessage": "Unable to execute HTTP request: Read timed out",
  "errorType": "com.amazonaws.SdkClientException",
  "stackTrace": [
    cause": {
      "errorMessage": "Read timed out",
   "errorType": "java.net.SocketTimeoutException",
   "stackTrace": [
  "java.net.SocketInputStream.socketRead0(Native Method)",
  "java.net.SocketInputStream.socketRead(SocketInputStream.java:116)",
  "java.net.SocketInputStream.read(SocketInputStream.java:171)",
  "java.net.SocketInputStream.read(SocketInputStream.java:141)",
  "sun.security.ssl.InputRecord.readFully(InputRecord.java:465)",
  "sun.security.ssl.InputRecord.read(InputRecord.java:503)",
  "sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:983)",
  "sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:940)",
  "sun.security.ssl.AppInputStream.read(AppInputStream.java:105)",

这是代码,你可以看到我尝试使用4个不同的命令来提高超时时间。

  // (2) Instantiate AWSLambdaClientBuilder to build the Lambda client
        AWSLambdaClientBuilder builder = 
 AWSLambdaClientBuilder.standard().withRegion(region);
        // (3) Build the client, which will ultimately invoke 
   the function
        AWSLambda client = builder.build();
        
        // (4) Create an InvokeRequest with required parameters
        InvokeRequest req = new 
   InvokeRequest().withFunctionName(random_arn).withPayload(jsonString); 
        
        // (5) Invoke the function and capture response
        int timeout = (15*60*1000);
        req.setSdkClientExecutionTimeout(timeout);
        req.setSdkRequestTimeout(timeout);
        req.withSdkClientExecutionTimeout(timeout);
        req.withSdkRequestTimeout(timeout);
        
        InvokeResult result = client.invoke(req);

有什么办法解决这个超时问题吗?
2个回答

5
当使用AWS Lambda时,您可能会对超时时间感兴趣。您提到的是函数执行超时时间-通常在讨论Lambda时人们所指的超时时间。但是,您还需要配置其他超时时间。请查看AWS CLI文档:https://docs.aws.amazon.com/cli/latest/reference/index.html。这里有--cli-read-timeout和--cli-connect-timeout。假设我创建一个具有5分钟函数执行超时时间的Lambda函数,并使用RequestResponse(同步)调用类型使用AWS CLI调用它,如果执行需要超过1分钟(--cli-read-timeout的默认值),则AWS Lambda将失败此执行并触发自动重试,最多重试一定次数。根据您的描述,我相信您正在遇到这种问题。请设置所有超时时间并再次尝试。以下链接可能对您有帮助:AWS Lambda使用Java-设置配置连接/套接字超时https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/section-client-configuration.htmlhttps://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/ClientConfiguration.html#setSocketTimeout-int-

1
是的,你说得对。经过一番搜索,我找到了适用于此的代码:ClientConfiguration clientConfiguration = new ClientConfiguration(); clientConfiguration.setSocketTimeout(0); AWSLambdaClientBuilder builder = AWSLambdaClientBuilder.standard() .withClientConfiguration(clientConfiguration) .withRegion(region); // (3) 构建客户端,最终将调用函数 AWSLambda client = builder.build(); - helloworld

2
由于您没有明确指定调用类型,因此您会同步地从第一个AWS Lambda中调用第二个AWS Lambda函数。因此,在第二个AWS Lambda函数运行时,第一个函数也将继续运行,等待第二个函数的响应。这就是为什么如果第一个和第二个AWS Lambda函数的运行时间总和高于第一个AWS Lambda函数的配置最大超时时间(在您的情况下为15分钟),则第一个AWS Lambda函数将超时的原因。
从另一个AWS Lambda函数同步调用AWS Lambda函数是不好的做法,因为您可能会遇到超时问题,就像您现在经历的那样,并且在第二个AWS Lambda函数正在运行时花费资金来运行第一个AWS Lambda函数。
您可以执行的操作是异步地调用第二个AWS Lambda函数,通过为您的InvokeRequest 设置适当的调用类型
InvokeRequest req = new InvokeRequest().withFunctionName(random_arn)
                                       .withPayload(jsonString)
                                       .withInvocationType(InvocationType.Event); 

当然,这只适用于您的第一个函数不依赖于第二个AWS Lambda函数的输出的情况。
也许更好的选择是使用AWS Step Functions来编排调用第二个AWS Lambda函数,正如以下教程所描述的那样:https://aws.amazon.com/de/getting-started/tutorials/create-a-serverless-workflow-step-functions-lambda/ 根据您的AWS Lambda函数的运行方式,将当前调用第二个AWS Lambda函数的第一个AWS Lambda函数拆分为在调用Lambda函数之前和之后运行的两个部分可能是有意义的。

嗨,感谢您详细的回复。我知道同步运行这两个 Lambda 的不足之处。我应该提到我在另一个区域中调用第二个 Lambda,这是无法在步骤函数管道中完成的,因为所有 Lambda 都需要在同一区域中运行(如果我有错,请纠正我,我很想在步骤函数中调用不同区域的 Lambda!)。是的,第一个 Lambda 应该耐心等待第二个 Lambda 完成。幸运的是,我可以使用相当少的内存运行第一个 Lambda。 - helloworld
第二个 lambda 执行繁重的任务(并使用更多内存)。因此,我有一些开销,但它不是巨大的。所以我认为我仍然需要等待我的第二个 lambda 完成,并继续使用该运行产生的 json 结果。我错过了什么吗?希望我错过了什么 :-) - helloworld
1
我仍然建议将调用Lambda函数拆分为两部分。一部分是直到触发第二个Lambda函数,另一部分是处理结果。由于您无法使用Step Functions进行编排,因此可以使用其他东西,例如SQS来持久化结果。因此,您将异步调用函数,并且具有在SQS队列中通过新消息触发结果处理Lambda函数的结果,这些消息由在其他区域中调用的Lambda函数写入。 - Dunedan
嗨Dunedan,那也是一个非常有趣和优雅的解决方案。我本来想将一些东西发布到s3上,但使用SQS更好。然而,我发现了一个超时设置,也可以工作,这要简单得多。 - helloworld

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接