1- //
2- // AWSLambda.java
3- //
4- // Copyright (c) 2013 Amazon. All rights reserved.
5- //
1+ /*
2+ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+ SPDX-License-Identifier: Apache-2.0
4+ */
65package com .amazonaws .services .lambda .runtime .api .client ;
76
87import com .amazonaws .services .lambda .crac .Core ;
1211import com .amazonaws .services .lambda .runtime .api .client .logging .LambdaContextLogger ;
1312import com .amazonaws .services .lambda .runtime .api .client .logging .LogSink ;
1413import com .amazonaws .services .lambda .runtime .api .client .logging .StdOutLogSink ;
15- import com .amazonaws .services .lambda .runtime .api .client .runtimeapi .InvocationRequest ;
16- import com .amazonaws .services .lambda .runtime .api .client .runtimeapi .LambdaRuntimeClient ;
14+ import com .amazonaws .services .lambda .runtime .api .client .runtimeapi .LambdaRuntimeApiClient ;
15+ import com .amazonaws .services .lambda .runtime .api .client .runtimeapi .LambdaRuntimeApiClientImpl ;
16+ import com .amazonaws .services .lambda .runtime .api .client .runtimeapi .converters .LambdaErrorConverter ;
17+ import com .amazonaws .services .lambda .runtime .api .client .runtimeapi .converters .XRayErrorCauseConverter ;
18+ import com .amazonaws .services .lambda .runtime .api .client .runtimeapi .dto .InvocationRequest ;
19+ import com .amazonaws .services .lambda .runtime .api .client .runtimeapi .dto .LambdaError ;
20+ import com .amazonaws .services .lambda .runtime .api .client .runtimeapi .dto .XRayErrorCause ;
1721import com .amazonaws .services .lambda .runtime .api .client .util .LambdaOutputStream ;
1822import com .amazonaws .services .lambda .runtime .api .client .util .UnsafeUtil ;
1923import com .amazonaws .services .lambda .runtime .logging .LogFormat ;
2024import com .amazonaws .services .lambda .runtime .logging .LogLevel ;
21- import com .amazonaws .services .lambda .runtime .serialization .PojoSerializer ;
22- import com .amazonaws .services .lambda .runtime .serialization .factories .GsonFactory ;
23- import com .amazonaws .services .lambda .runtime .serialization .factories .JacksonFactory ;
2425import com .amazonaws .services .lambda .runtime .serialization .util .ReflectUtil ;
2526
2627import java .io .ByteArrayOutputStream ;
2728import java .io .File ;
2829import java .io .FileDescriptor ;
2930import java .io .FileInputStream ;
31+ import java .io .IOError ;
3032import java .io .IOException ;
31- import java .io .OutputStream ;
3233import java .io .PrintStream ;
3334import java .lang .reflect .Constructor ;
3435import java .net .URLClassLoader ;
@@ -67,6 +68,10 @@ public class AWSLambda {
6768
6869 private static final String AWS_LAMBDA_INITIALIZATION_TYPE = System .getenv (ReservedRuntimeEnvironmentVariables .AWS_LAMBDA_INITIALIZATION_TYPE );
6970
71+ protected static URLClassLoader customerClassLoader ;
72+
73+ private static LambdaRuntimeApiClient runtimeClient ;
74+
7075 static {
7176 // Override the disabledAlgorithms setting to match configuration for openjdk8-u181.
7277 // This is to keep DES ciphers around while we deploying security updates.
@@ -143,17 +148,6 @@ public static void setupRuntimeLogger(LambdaLogger lambdaLogger)
143148 );
144149 }
145150
146- public static String getEnvOrExit (String envVariableName ) {
147- String value = System .getenv (envVariableName );
148- if (value == null ) {
149- System .err .println ("Could not get environment variable " + envVariableName );
150- System .exit (-1 );
151- }
152- return value ;
153- }
154-
155- protected static URLClassLoader customerClassLoader ;
156-
157151 /**
158152 * convert an integer into a FileDescriptor object using reflection to access private members.
159153 */
@@ -207,8 +201,7 @@ private static void startRuntime(String handler, LambdaContextLogger lambdaLogge
207201 System .setErr (new PrintStream (new LambdaOutputStream (System .err ), false , "UTF-8" ));
208202 setupRuntimeLogger (lambdaLogger );
209203
210- String runtimeApi = getEnvOrExit (ReservedRuntimeEnvironmentVariables .AWS_LAMBDA_RUNTIME_API );
211- LambdaRuntimeClient runtimeClient = new LambdaRuntimeClient (runtimeApi );
204+ runtimeClient = new LambdaRuntimeApiClientImpl (LambdaEnvironment .RUNTIME_API );
212205
213206 String taskRoot = System .getProperty ("user.dir" );
214207 String libRoot = "/opt/java" ;
@@ -223,17 +216,18 @@ private static void startRuntime(String handler, LambdaContextLogger lambdaLogge
223216 requestHandler = findRequestHandler (handler , customerClassLoader );
224217 } catch (UserFault userFault ) {
225218 lambdaLogger .log (userFault .reportableError (), lambdaLogger .getLogFormat () == LogFormat .JSON ? LogLevel .ERROR : LogLevel .UNDEFINED );
226- reportInitError (new Failure (userFault ), runtimeClient );
219+ LambdaError error = LambdaErrorConverter .fromUserFault (userFault );
220+ runtimeClient .reportInitError (error );
227221 System .exit (1 );
228222 return ;
229223 }
230224 if (INIT_TYPE_SNAP_START .equals (AWS_LAMBDA_INITIALIZATION_TYPE )) {
231- onInitComplete (runtimeClient , lambdaLogger );
225+ onInitComplete (lambdaLogger );
232226 }
233227 boolean shouldExit = false ;
234228 while (!shouldExit ) {
235229 UserFault userFault = null ;
236- InvocationRequest request = runtimeClient .waitForNextInvocation ();
230+ InvocationRequest request = runtimeClient .nextInvocation ();
237231 if (request .getXrayTraceId () != null ) {
238232 System .setProperty (LAMBDA_TRACE_HEADER_PROP , request .getXrayTraceId ());
239233 } else {
@@ -243,26 +237,23 @@ private static void startRuntime(String handler, LambdaContextLogger lambdaLogge
243237 ByteArrayOutputStream payload ;
244238 try {
245239 payload = requestHandler .call (request );
246- runtimeClient .postInvocationResponse (request .getId (), payload .toByteArray ());
240+ runtimeClient .reportInvocationSuccess (request .getId (), payload .toByteArray ());
247241 boolean ignored = Thread .interrupted (); // clear interrupted flag in case if it was set by user's code
248242 } catch (UserFault f ) {
243+ shouldExit = f .fatal ;
249244 userFault = f ;
250245 UserFault .filterStackTrace (f );
251- payload = new ByteArrayOutputStream (1024 );
252- Failure failure = new Failure (f );
253- GsonFactory .getInstance ().getSerializer (Failure .class ).toJson (failure , payload );
254- shouldExit = f .fatal ;
255- runtimeClient .postInvocationError (request .getId (), payload .toByteArray (), failure .getErrorType ());
246+
247+ LambdaError error = LambdaErrorConverter .fromUserFault (f );
248+ runtimeClient .reportInvocationError (request .getId (), error );
256249 } catch (Throwable t ) {
250+ shouldExit = t instanceof VirtualMachineError || t instanceof IOError ;
257251 UserFault .filterStackTrace (t );
258252 userFault = UserFault .makeUserFault (t );
259- payload = new ByteArrayOutputStream (1024 );
260- Failure failure = new Failure (t );
261- GsonFactory .getInstance ().getSerializer (Failure .class ).toJson (failure , payload );
262- // These two categories of errors are considered fatal.
263- shouldExit = Failure .isInvokeFailureFatal (t );
264- runtimeClient .postInvocationError (request .getId (), payload .toByteArray (), failure .getErrorType (),
265- serializeAsXRayJson (t ));
253+
254+ LambdaError error = LambdaErrorConverter .fromThrowable (t );
255+ XRayErrorCause xRayErrorCause = XRayErrorCauseConverter .fromThrowable (t );
256+ runtimeClient .reportInvocationError (request .getId (), error , xRayErrorCause );
266257 } finally {
267258 if (userFault != null ) {
268259 lambdaLogger .log (userFault .reportableError (), lambdaLogger .getLogFormat () == LogFormat .JSON ? LogLevel .ERROR : LogLevel .UNDEFINED );
@@ -271,23 +262,22 @@ private static void startRuntime(String handler, LambdaContextLogger lambdaLogge
271262 }
272263 }
273264
274- static void onInitComplete (final LambdaRuntimeClient runtimeClient , final LambdaContextLogger lambdaLogger ) throws IOException {
265+ static void onInitComplete (final LambdaContextLogger lambdaLogger ) throws IOException {
275266 try {
276267 Core .getGlobalContext ().beforeCheckpoint (null );
277- // Blocking call to RAPID /restore/next API, will return after taking snapshot.
278- // This will also be the 'entrypoint' when resuming from snapshots.
279- runtimeClient .getRestoreNext ();
268+ runtimeClient .restoreNext ();
280269 } catch (Exception e1 ) {
281270 logExceptionCloudWatch (lambdaLogger , e1 );
282- reportInitError (new Failure (e1 ), runtimeClient );
271+ LambdaError error = LambdaErrorConverter .fromThrowable (e1 );
272+ runtimeClient .reportInitError (error );
283273 System .exit (64 );
284274 }
285275 try {
286276 Core .getGlobalContext ().afterRestore (null );
287277 } catch (Exception restoreExc ) {
288278 logExceptionCloudWatch (lambdaLogger , restoreExc );
289- Failure errorPayload = new Failure (restoreExc );
290- reportRestoreError (errorPayload , runtimeClient );
279+ LambdaError error = LambdaErrorConverter . fromThrowable (restoreExc );
280+ runtimeClient . reportRestoreError (error );
291281 System .exit (64 );
292282 }
293283 }
@@ -297,40 +287,4 @@ private static void logExceptionCloudWatch(LambdaContextLogger lambdaLogger, Exc
297287 UserFault userFault = UserFault .makeUserFault (exc , true );
298288 lambdaLogger .log (userFault .reportableError (), lambdaLogger .getLogFormat () == LogFormat .JSON ? LogLevel .ERROR : LogLevel .UNDEFINED );
299289 }
300-
301- static void reportInitError (final Failure failure ,
302- final LambdaRuntimeClient runtimeClient ) throws IOException {
303-
304- ByteArrayOutputStream payload = new ByteArrayOutputStream (1024 );
305- JacksonFactory .getInstance ().getSerializer (Failure .class ).toJson (failure , payload );
306- runtimeClient .postInitError (payload .toByteArray (), failure .getErrorType ());
307- }
308-
309- static int reportRestoreError (final Failure failure ,
310- final LambdaRuntimeClient runtimeClient ) throws IOException {
311-
312- ByteArrayOutputStream payload = new ByteArrayOutputStream (1024 );
313- JacksonFactory .getInstance ().getSerializer (Failure .class ).toJson (failure , payload );
314- return runtimeClient .postRestoreError (payload .toByteArray (), failure .getErrorType ());
315- }
316-
317- private static PojoSerializer <XRayErrorCause > xRayErrorCauseSerializer ;
318-
319- /**
320- * @param throwable throwable to convert
321- * @return json as string expected by XRay's web console. On conversion failure, returns null.
322- */
323- private static String serializeAsXRayJson (Throwable throwable ) {
324- try {
325- final OutputStream outputStream = new ByteArrayOutputStream ();
326- final XRayErrorCause cause = new XRayErrorCause (throwable );
327- if (xRayErrorCauseSerializer == null ) {
328- xRayErrorCauseSerializer = JacksonFactory .getInstance ().getSerializer (XRayErrorCause .class );
329- }
330- xRayErrorCauseSerializer .toJson (cause , outputStream );
331- return outputStream .toString ();
332- } catch (Exception e ) {
333- return null ;
334- }
335- }
336290}
0 commit comments