Spring Boot deployed in Lambda throws "statusCode": 502 Gateway timeout"
P粉111227898
2023-08-28 23:12:36
<p>我将 Spring boot jar 文件(它具有 lambda 请求流处理程序)作为 zip 文件上传到 AWS Lambda。由于 zip 很大,我在 S3 中上传并在 AWS 控制台中创建此 Lambda 函数时给出了该链接。正如我到处读到的那样,这就是使用简单方法在 lambda 中部署 Spring Boot 服务的全部内容。我的 Spring Boot 服务中有 2 个 GET 端点。请在下面找到完整的 Spring boot 服务代码和 Lambda 屏幕截图。</p>
<p>错误:(出现超时错误,因此在 Lambda 测试中增加到 15 分钟,结果如下,似乎仍然无法正常工作)</p>
<pre class="brush:php;toolbar:false;">Executing function: succeeded (logs )
{
"statusCode": 502,
"multiValueHeaders": {
"Content-Type": [
"application/json"
]
},
"body": "{\"message\":\"Gateway timeout\"}",
"isBase64Encoded": false
}</pre>
<p>Spring boot Lambda 请求流处理程序:(异步,因为我觉得 Lambda 最初需要很长时间才能启动)</p>
<pre class="brush:php;toolbar:false;">public class StreamLambdaHandler implements RequestStreamHandler {
private SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
public StreamLambdaHandler() throws ContainerInitializationException {
handler = new SpringBootProxyHandlerBuilder()
.defaultProxy()
.asyncInit()
.springBootApplication(SlowApplication.class)
.buildAndInitialize();
}
@Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
handler.proxyStream(inputStream, outputStream, context);
}
}</pre>
<p>build.gradle(我在此处添加了“task buildZip”以获取 zip 文件中的 build->“distributions”jar)</p>
<pre class="brush:php;toolbar:false;">plugins {
id 'java'
id 'org.springframework.boot' version '3.1.0'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'mysql:mysql-connector-java:8.0.32'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'com.amazonaws:aws-lambda-java-core:1.2.2'
implementation 'com.amazonaws:aws-lambda-java-events:3.11.1'
implementation 'com.amazonaws.serverless:aws-serverless-java-container-spring:1.5.2'
}
task buildZip(type: Zip) {
into('lib') {
from(jar)
from(configurations.runtimeClasspath)
}
}
tasks.named('test') {
useJUnitPlatform()
}
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
manifest {
attributes "Main-Class": "com.example.awstest"
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}</pre>
<p>Spring Boot应用程序类:</p>
<pre class="brush:php;toolbar:false;">package com.example.awstest.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@ComponentScan ("com.example.awstest")
public class AWSTestApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(AWSTestApplication.class, args);
}
}</pre>
<p>Spring 启动控制器:</p>
<pre class="brush:php;toolbar:false;">package com.example.awstest.controller;
@RestController
public class AWSTestController {
@Autowired
private AWSTestServiceDAO awstestServiceDAO;
@CrossOrigin(origins = "*")
@GetMapping("/searchAllData")
public List<TESTData> searchAllData() {
List<TESTData> dataList = awstestServiceDAO.getAllData();
return dataList;
}
@CrossOrigin(origins = "*")
@GetMapping("/searchDataByUser/{userno}")
public List<TESTData> searchDataByUser(@PathVariable Integer userno) {
List<TESTData> dataList = awstestServiceDAO.findDataByMemberNo(userno);
return dataList;
}
}</pre>
<p>Lambda 控制台:</p>
<p>添加处理程序为:<code>com.example.awstest.handler.AWSLambdaHandler::handleRequest</code></p>
<p>测试功能:apigateway-awsproxy</p>
<pre class="brush:php;toolbar:false;">{
"body": "eyJ0ZXN0IjoiYm9keSJ9",
"resource": "/{proxy+}",
"path": "/searchAllData",
"httpMethod": "GET",
"isBase64Encoded": true,
"pathParameters": {
"proxy": "/searchAllData"
},
"stageVariables": {
"baz": "qux"
},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, sdch",
"Accept-Language": "en-US,en;q=0.8",
"Cache-Control": "max-age=0",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "US",
"Host": "1234567890.execute-api.us-east-1.amazonaws.com",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Custom User Agent String",
"Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",
"X-Forwarded-For": "127.0.0.1, 127.0.0.2",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"multiValueHeaders": {
"Accept": [
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
],
"Accept-Encoding": [
"gzip, deflate, sdch"
],
"Accept-Language": [
"en-US,en;q=0.8"
],
"Cache-Control": [
"max-age=0"
],
"CloudFront-Forwarded-Proto": [
"https"
],
"CloudFront-Is-Desktop-Viewer": [
"true"
],
"CloudFront-Is-Mobile-Viewer": [
"false"
],
"CloudFront-Is-SmartTV-Viewer": [
"false"
],
"CloudFront-Is-Tablet-Viewer": [
"false"
],
"CloudFront-Viewer-Country": [
"US"
],
"Host": [
"0123456789.execute-api.us-east-1.amazonaws.com"
],
"Upgrade-Insecure-Requests": [
"1"
],
"User-Agent": [
"Custom User Agent String"
],
"Via": [
"1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)"
],
"X-Amz-Cf-Id": [
"cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA=="
],
"X-Forwarded-For": [
"127.0.0.1, 127.0.0.2"
],
"X-Forwarded-Port": [
"443"
],
"X-Forwarded-Proto": [
"https"
]
},
"requestContext": {
"accountId": "123456789012",
"resourceId": "123456",
"stage": "prod",
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
"requestTime": "09/Apr/2015:12:34:56 +0000",
"requestTimeEpoch": 1428582896000,
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"accessKey": null,
"sourceIp": "127.0.0.1",
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "Custom User Agent String",
"user": null
},
"path": "/prod/searchAllData",
"resourcePath": "/{proxy+}",
"httpMethod": "GET",
"apiId": "1234567890",
"protocol": "HTTP/1.1"
}
}</pre>
<p>错误:</p>
<pre class="brush:php;toolbar:false;">s.exceptions.ContainerInitializationException: Could not initialize framework within the 20000ms timeout
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:207)
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxyStream(LambdaContainerHandler.java:254)
at com.example.awstest.handler.AWSLambdaHandler.handleRequest(AWSLambdaHandler.java:36)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at com.amazonaws.services.lambda.runtime.api.client.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:379)
at com.amazonaws.services.lambda.runtime.api.client.EventHandlerLoader$2.call(EventHandlerLoader.java:903)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:238)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:190)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.main(AWSLambda.java:185)
04:36:48.470 [main] ERROR com.amazonaws.serverless.proxy.AwsProxyExceptionHandler -- Called exception handler for:
com.amazonaws.serverless.exceptions.ContainerInitializationException: Could not initialize framework within the 20000ms timeout
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:207)
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxyStream(LambdaContainerHandler.java:254)
at com.example.awstest.handler.AWSLambdaHandler.handleRequest(AWSLambdaHandler.java:36)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at com.amazonaws.services.lambda.runtime.api.client.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:379)
at com.amazonaws.services.lambda.runtime.api.client.EventHandlerLoader$2.call(EventHandlerLoader.java:903)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:238)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:190)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.main(AWSLambda.java:185)
com.amazonaws.serverless.exceptions.ContainerInitializationException: Could not initialize framework within the 20000ms timeout
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:207)
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxyStream(LambdaContainerHandler.java:254)
at com.example.awstest.handler.AWSLambdaHandler.handleRequest(AWSLambdaHandler.java:36)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at com.amazonaws.services.lambda.runtime.api.client.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:379)
at com.amazonaws.services.lambda.runtime.api.client.EventHandlerLoader$2.call(EventHandlerLoader.java:903)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:238)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.startRuntime(AWSLambda.java:190)
at com.amazonaws.services.lambda.runtime.api.client.AWSLambda.main(AWSLambda.java:185)
END RequestId: 21464e19-8dee-47e0-9acd-5ae04d24431a
REPORT RequestId: 21464e19-8dee-47e0-9acd-5ae04d24431a Duration: 20003.03 ms Billed Duration: 20004 ms Memory Size: 512 MB Max Memory Used: 137 MB</pre></p>
Looking at your Gradle files, you are using a very old and outdated version of the AWS Serverless Java container that is not compatible with Spring Boot 3.x.
Remove
com.amazonaws.serverless:aws-serverless-java-container-spring:1.5.2
and replace it withcom.amazonaws.serverless:aws-serverless-java-container -springboot3:2.0.0-M1
. You can also compare at https://github.com/awslabs/aws-serverless-java-container/tree/main/samples/springboot3/pet-store.If you encounter similar timeout challenges in the future, you can also enable AWS X-Ray or OpenTelemetry to collect tracking data and see where time is lost.