Skip to content

Commit 7a3954f

Browse files
authored
Merge branch 'graalvm' into after-burner-native
2 parents 3a04d8c + 3e55220 commit 7a3954f

File tree

24 files changed

+1133
-15
lines changed

24 files changed

+1133
-15
lines changed

Dockerfile

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
FROM amazonlinux:2017.03.1.20170812 as graalvm
2+
# install graal to amazon linux.
3+
ENV LANG=en_US.UTF-8
4+
5+
RUN yum install -y gcc gcc-c++ libc6-dev zlib1g-dev curl bash zlib zlib-devel zip \
6+
&& rm -rf /var/cache/yum
7+
8+
# Install JDK8 with backported JVMCI
9+
ENV JDK_FILE openjdk-8u242-jvmci-20.1-b01-linux-amd64
10+
ENV JDK_DIR openjdk1.8.0_242-jvmci-20.1-b01
11+
RUN curl -4 -L https://github.com/graalvm/openjdk8-jvmci-builder/releases/download/jvmci-20.1-b01/${JDK_FILE}.tar.gz -o /tmp/jdk.tar.gz
12+
RUN tar -zxvf /tmp/jdk.tar.gz -C /tmp \
13+
&& mv /tmp/${JDK_DIR} /usr/lib/jdk
14+
ENV JAVA_HOME /usr/lib/jdk
15+
16+
# Download and install GraalVM 20.0.0 + native image
17+
ENV GRAAL_VERSION 20.0.0
18+
ENV GRAAL_FILENAME graalvm-ce-java8-linux-amd64-${GRAAL_VERSION}.tar.gz
19+
RUN curl -4 -L https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-${GRAAL_VERSION}/${GRAAL_FILENAME} -o /tmp/${GRAAL_FILENAME}
20+
RUN tar -zxvf /tmp/${GRAAL_FILENAME} -C /tmp \
21+
&& mv /tmp/graalvm-ce-java8-${GRAAL_VERSION} /usr/lib/graalvm
22+
RUN /usr/lib/graalvm/bin/gu install native-image
23+
24+
# Download and install maven
25+
ENV MAVEN_VERSION 3.6.3
26+
RUN curl -4 -L http://apache.forsale.plus/maven/maven-3/3.6.3/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz -o /tmp/maven.tar.gz
27+
RUN tar -zxvf /tmp/maven.tar.gz -C /tmp \
28+
&& mv /tmp/apache-maven-${MAVEN_VERSION} /usr/lib/maven
29+
30+
RUN rm -rf /tmp/*
31+
32+
ENV PATH /usr/lib/graalvm/bin:/usr/lib/maven/bin:${PATH}
33+
34+
COPY . /usr/lib/sjc
35+
RUN cd /usr/lib/sjc && mvn install -DskipTests -Djacoco.minCoverage=0.1
36+
37+
VOLUME ["/func"]
38+
WORKDIR /func
39+
ENTRYPOINT ["/func/scripts/graalvm-build.sh"]

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import com.fasterxml.jackson.databind.ObjectMapper;
2525
import com.fasterxml.jackson.databind.ObjectReader;
2626
import com.fasterxml.jackson.databind.ObjectWriter;
27-
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
27+
//import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
2828
import org.slf4j.Logger;
2929
import org.slf4j.LoggerFactory;
3030

@@ -84,6 +84,7 @@ public abstract class LambdaContainerHandler<RequestType, ResponseType, Containe
8484
registerAfterBurner();
8585
}
8686

87+
8788
private static void registerAfterBurner() {
8889
objectMapper.registerModule(new AfterburnerModule());
8990
}

aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringBootAppTest.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
55
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
66
import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
7-
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
87
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
98
import com.amazonaws.serverless.proxy.model.Headers;
109
import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap;
@@ -25,8 +24,7 @@
2524
import java.util.Collection;
2625
import java.util.Objects;
2726

28-
import static com.amazonaws.serverless.proxy.spring.springbootapp.TestController.CUSTOM_HEADER_NAME;
29-
import static com.amazonaws.serverless.proxy.spring.springbootapp.TestController.CUSTOM_QS_NAME;
27+
import static com.amazonaws.serverless.proxy.spring.springbootapp.TestController.*;
3028
import static org.junit.Assert.*;
3129
import static org.junit.Assume.assumeFalse;
3230

@@ -187,7 +185,6 @@ public void utf8_returnUtf8String_expectCorrectHeaderMediaAndCharsetNoDefault()
187185
assertTrue(output.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE).contains("charset=UTF-8"));
188186
}
189187

190-
191188
private void validateSingleValueModel(AwsProxyResponse output, String value) {
192189
try {
193190
SingleValueModel response = mapper.readValue(output.getBody(), SingleValueModel.class);

aws-serverless-java-container-springboot2/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootLambdaContainerHandler.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
import com.amazonaws.serverless.exceptions.ContainerInitializationException;
1616
import com.amazonaws.serverless.proxy.*;
17-
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
1817
import com.amazonaws.serverless.proxy.internal.servlet.*;
1918
import com.amazonaws.serverless.proxy.internal.testutils.Timer;
2019
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
@@ -25,18 +24,12 @@
2524
import com.amazonaws.services.lambda.runtime.Context;
2625
import org.slf4j.Logger;
2726
import org.slf4j.LoggerFactory;
28-
import org.springframework.boot.SpringApplication;
2927
import org.springframework.boot.WebApplicationType;
3028
import org.springframework.boot.builder.SpringApplicationBuilder;
31-
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
29+
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
3230
import org.springframework.context.ConfigurableApplicationContext;
33-
import org.springframework.core.env.ConfigurableEnvironment;
34-
import org.springframework.core.env.StandardEnvironment;
35-
import org.springframework.web.context.ConfigurableWebApplicationContext;
36-
import org.springframework.web.servlet.DispatcherServlet;
3731

3832
import javax.servlet.Servlet;
39-
import javax.servlet.ServletRegistration;
4033
import javax.servlet.http.HttpServletRequest;
4134
import java.util.concurrent.CountDownLatch;
4235

@@ -194,7 +187,7 @@ public void initialize()
194187
}
195188
applicationContext = builder.run();
196189
if (springWebApplicationType == WebApplicationType.SERVLET) {
197-
((AnnotationConfigServletWebServerApplicationContext)applicationContext).setServletContext(getServletContext());
190+
((ServletWebServerApplicationContext)applicationContext).setServletContext(getServletContext());
198191
AwsServletRegistration reg = (AwsServletRegistration)getServletContext().getServletRegistration(DISPATCHER_SERVLET_REGISTRATION_NAME);
199192
if (reg != null) {
200193
reg.setLoadOnStartup(1);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.amazonaws.serverless.runtime;
2+
3+
import com.amazonaws.services.lambda.runtime.ClientContext;
4+
import com.amazonaws.services.lambda.runtime.CognitoIdentity;
5+
import com.amazonaws.services.lambda.runtime.Context;
6+
import com.amazonaws.services.lambda.runtime.LambdaLogger;
7+
8+
import java.time.Instant;
9+
10+
public class InvocationContext implements Context {
11+
private static final String FUNCTION_NAME_ENV_VAR = "AWS_LAMBDA_FUNCTION_NAME";
12+
private static final String FUNCTION_LOG_STREAM_ENV_VAR = "AWS_LAMBDA_LOG_STREAM_NAME";
13+
private static final String FUNCTION_LOG_GROUP_ENV_VAR = "AWS_LAMBDA_LOG_GROUP_NAME";
14+
private static final String FUNCTION_VERSION_ENV_VAR = "AWS_LAMBDA_FUNCTION_VERSION";
15+
private static final String FUNCTION_MEMORY_ENV_VAR = "AWS_LAMBDA_FUNCTION_MEMORY_SIZE";
16+
17+
private static String functionName;
18+
private static String logGroupName;
19+
private static String logStreamName;
20+
private static String functionVersion;
21+
private static int memoryLimitMb;
22+
23+
public static void prepareContext() {
24+
functionName = System.getenv(FUNCTION_NAME_ENV_VAR);
25+
logGroupName = System.getenv(FUNCTION_LOG_GROUP_ENV_VAR);
26+
logStreamName = System.getenv(FUNCTION_LOG_STREAM_ENV_VAR);
27+
functionVersion = System.getenv(FUNCTION_VERSION_ENV_VAR);
28+
memoryLimitMb = Integer.parseInt(System.getenv(FUNCTION_MEMORY_ENV_VAR));
29+
}
30+
31+
private String awsRequestId;
32+
private long deadlineMs;
33+
private String functionArn;
34+
private String traceId;
35+
36+
public InvocationContext(String reqId, long deadline, String arn, String trace) {
37+
awsRequestId = reqId;
38+
deadlineMs = deadline;
39+
functionArn = arn;
40+
traceId = trace;
41+
}
42+
43+
@Override
44+
public String getAwsRequestId() {
45+
return awsRequestId;
46+
}
47+
48+
@Override
49+
public String getLogGroupName() {
50+
return logGroupName;
51+
}
52+
53+
@Override
54+
public String getLogStreamName() {
55+
return logStreamName;
56+
}
57+
58+
@Override
59+
public String getFunctionName() {
60+
return functionName;
61+
}
62+
63+
@Override
64+
public String getFunctionVersion() {
65+
return functionVersion;
66+
}
67+
68+
@Override
69+
public String getInvokedFunctionArn() {
70+
return functionArn;
71+
}
72+
73+
@Override
74+
public CognitoIdentity getIdentity() {
75+
return null;
76+
}
77+
78+
@Override
79+
public ClientContext getClientContext() {
80+
return null;
81+
}
82+
83+
@Override
84+
public int getRemainingTimeInMillis() {
85+
return Math.toIntExact(deadlineMs - Instant.now().toEpochMilli());
86+
}
87+
88+
@Override
89+
public int getMemoryLimitInMB() {
90+
return memoryLimitMb;
91+
}
92+
93+
@Override
94+
public LambdaLogger getLogger() {
95+
return null;
96+
}
97+
98+
public String getTraceId() {
99+
return traceId;
100+
}
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.amazonaws.serverless.runtime;
2+
3+
import com.amazonaws.services.lambda.runtime.Context;
4+
5+
import java.io.InputStream;
6+
7+
public class InvocationRequest {
8+
private InputStream event;
9+
private Context context;
10+
11+
public InputStream getEvent() {
12+
return event;
13+
}
14+
15+
public void setEvent(InputStream event) {
16+
this.event = event;
17+
}
18+
19+
public Context getContext() {
20+
return context;
21+
}
22+
23+
public void setContext(Context context) {
24+
this.context = context;
25+
}
26+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package com.amazonaws.serverless.runtime;
2+
3+
import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
4+
import com.amazonaws.services.lambda.runtime.Context;
5+
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
6+
7+
import java.io.ByteArrayOutputStream;
8+
import java.io.IOException;
9+
import java.io.InputStream;
10+
import java.io.OutputStream;
11+
12+
public class Runtime implements RequestStreamHandler {
13+
private static final int MAX_RETRIES = 3;
14+
15+
private final int maxRetries;
16+
private final SpringBootLambdaContainerHandler<?, ?> handler;
17+
18+
public Runtime(SpringBootLambdaContainerHandler<?, ?> handler) {
19+
this(handler, MAX_RETRIES);
20+
}
21+
22+
public Runtime(SpringBootLambdaContainerHandler<?, ?> handler, int retries) {
23+
maxRetries = retries;
24+
this.handler = handler;
25+
}
26+
27+
public void start() {
28+
RuntimeClient client = new RuntimeClient();
29+
start(client);
30+
}
31+
32+
public void start(RuntimeClient client) throws RuntimeException {
33+
while (true) {
34+
InvocationRequest req = getNextRequest(client);
35+
if (req == null) {
36+
throw new RuntimeException("Could not fetch next event after " + maxRetries + " attempts");
37+
}
38+
39+
ByteArrayOutputStream os = new ByteArrayOutputStream();
40+
try {
41+
handleRequest(req.getEvent(), os, req.getContext());
42+
} catch (IOException e) {
43+
e.printStackTrace();
44+
postErrorResponse(client, req.getContext().getAwsRequestId(), e);
45+
}
46+
47+
postResponse(client, req.getContext().getAwsRequestId(), os);
48+
}
49+
}
50+
51+
private InvocationRequest getNextRequest(RuntimeClient client) {
52+
InvocationRequest req;
53+
for (int i = 0; i < maxRetries; i++) {
54+
try {
55+
req = client.getNextEvent();
56+
return req;
57+
} catch (RuntimeClientException e) {
58+
if (!e.isRetriable()) {
59+
throw new RuntimeException("Failed to fetch next event", e);
60+
}
61+
}
62+
}
63+
return null;
64+
}
65+
66+
private void postResponse(RuntimeClient client, String reqId, OutputStream os) {
67+
for (int i = 0; i < maxRetries; i++) {
68+
try {
69+
client.postInvocationResponse(reqId, os);
70+
return;
71+
} catch (RuntimeClientException ex) {
72+
if (!ex.isRetriable()) {
73+
throw new RuntimeException("Failed to post invocation response", ex);
74+
}
75+
}
76+
}
77+
throw new RuntimeException("Failed to post invocation response " + maxRetries + " times");
78+
}
79+
80+
private void postErrorResponse(RuntimeClient client, String reqId, Throwable e) {
81+
for (int i = 0; i < maxRetries; i++) {
82+
try {
83+
client.postInvocationError(reqId, e);
84+
return;
85+
} catch (RuntimeClientException ex) {
86+
if (!ex.isRetriable()) {
87+
throw new RuntimeException("Failed to post invocation error", ex);
88+
}
89+
}
90+
}
91+
throw new RuntimeException("Failed to post invocation error response " + maxRetries + " times");
92+
}
93+
94+
@Override
95+
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
96+
handler.proxyStream(inputStream, outputStream, context);
97+
}
98+
}

0 commit comments

Comments
 (0)