Best practices for working with Lambda SnapStart
Network connections
The state of connections that your function establishes during the initialization phase isn't guaranteed when Lambda resumes your function from a snapshot. In most cases, network connections that an Amazon SDK establishes automatically resume. For other connections, we recommend the following best practices.
Re-establish network connections
Always re-establish your network connections when your function resumes from a snapshot. We recommend that you re-establish network connections in the function handler. Alternatively, you can use an afterRestore
runtime hook.
Don't use hostname as a unique execution environment identifier
We recommend against using hostname
to identify your execution environment as a unique node or
container in your applications. With SnapStart, a single snapshot is used as the initial state for multiple
execution environments, and all execution environments return the same hostname
value for
InetAddress.getLocalHost()
. For applications that require a unique execution environment identity
or hostname
value, we recommend that you generate a unique ID in the function handler. Or, use an
afterRestore
runtime hook to generate a unique ID, and then use the unique ID as
the identifier for the execution environment.
Avoid binding connections to fixed source ports
We recommend that you avoid binding network connections to fixed source ports. Connections are re-established when a function resumes from a snapshot, and network connections that are bound to a fixed source port might fail.
Avoid using Java DNS cache
Lambda functions already cache DNS responses. If you use another DNS cache with SnapStart, then you might experience connection timeouts when the function resumes from a snapshot.
Performance tuning
Note
SnapStart works best when used with function invocations at scale. Functions that are invoked infrequently might not experience the same performance improvements.
To maximize the benefits of SnapStart, we recommend that you preload classes that contribute to startup latency in your initialization code instead of in the function handler. This moves the latency associated with heavy class loading out of the invocation path, optimizing startup performance with SnapStart.
If you can't preload classes during initialization, then we recommend that you preload classes with dummy
invocations. To do this, update the function handler code, as shown in the following example from the pet store
function
private static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler; static { try { handler = SpringLambdaContainerHandler.getAwsProxyHandler(PetStoreSpringAppConfig.class); // Use the onStartup method of the handler to register the custom filter handler.onStartup(servletContext -> { FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter", CognitoIdentityFilter.class); registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*"); }); // Send a fake Amazon API Gateway request to the handler to load classes ahead of time ApiGatewayRequestIdentity identity = new ApiGatewayRequestIdentity(); identity.setApiKey("foo"); identity.setAccountId("foo"); identity.setAccessKey("foo"); AwsProxyRequestContext reqCtx = new AwsProxyRequestContext(); reqCtx.setPath("/pets"); reqCtx.setStage("default"); reqCtx.setAuthorizer(null); reqCtx.setIdentity(identity); AwsProxyRequest req = new AwsProxyRequest(); req.setHttpMethod("GET"); req.setPath("/pets"); req.setBody(""); req.setRequestContext(reqCtx); Context ctx = new TestContext(); handler.proxy(req, ctx); } catch (ContainerInitializationException e) { // if we fail here. We re-throw the exception to force another cold start e.printStackTrace(); throw new RuntimeException("Could not initialize Spring framework", e); } }