Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 10
Home
Welcome to the aws-lambda-snapstart-java-rules wiki!
Lambda SnapStart speeds up applications by re-using a single initialized snapshot to resume multiple execution environments. As a result, unique content included in the snapshot during initialization is reused across execution environments, and so may no longer remain unique. A class of applications where uniqueness of state is a key consideration is cryptographic software, which assumes that the random numbers are truly random (both random and unpredictable). If content such as a random seed is saved in the snapshot during initialization, it is re-used when multiple execution environments resume and may produce predictable random sequences.
To maintain uniqueness, you must verify before using SnapStart that any unique content previously generated during the initialization now gets generated after that initialization. This includes unique IDs, unique secrets, and entropy used to generate pseudo-randomness.
These are some examples that may lead to scenarios where your code does not maintain uniqueness with SnapStart.
Lambda functions that require pseudo-random values can initialize a pseudo-random number generator as below. Lambda SnapStart functions will snapshot the java.util.Random instance which will cause exactly the same sequence of random numbers to be generated in each execution environment that runs this SnapStart function.
importcom.amazonaws.services.lambda.runtime.Context;
importcom.amazonaws.services.lambda.runtime.RequestHandler;
importjava.util.Random;
publicclassLambdaWithRandomimplementsRequestHandler<String, String> {
privatefinalRandomrandom;
publicLambdaUsingRandom() {
// This is snapshotted by SnapStart, so it's a bugrandom = newRandom(); }
@OverridepublicStringhandleRequest(Stringevent, Contextcontext) {
// use random to generate a random number here.return"hello world";
}
}If this creates an issue for your Lambda application, you can make sure that each execution creates its own sequence of random numbers by using java.security.SecureRandom instead of java.util.Random as shown below.
importcom.amazonaws.services.lambda.runtime.Context;
importcom.amazonaws.services.lambda.runtime.RequestHandler;
importjava.security.SecureRandom;
publicclassLambdaWithRandomimplementsRequestHandler<String, String> {
privatefinalSecureRandomrandom;
publicLambdaUsingRandom() {
random = newSecureRandom(); }
@OverridepublicStringhandleRequest(Stringevent, Contextcontext) {
// use random to generate a random number here.return"hello world";
}
}A common use case for Lambda functions is to create a unique identifier that’s used by multiple invocations in the same execution environment such as a CloudWatch log stream name. Since SnapStart execution environments can start from the same snapshot, a random value that initializes a Lambda handler class member gets copied to multiple execution environments.
importcom.amazonaws.services.lambda.runtime.Context;
importcom.amazonaws.services.lambda.runtime.RequestHandler;
importjava.util.UUID;
publicclassLambdaLoggerimplementsRequestHandler<String, String> {
privateUUIDuniqueLogId;
publicLambdaUsingRandom() {
// This is snapshotted by SnapStart, so it's a buguniqueLogId = UUID.randomUUID(); }
@OverridepublicStringhandleRequest(Stringevent, Contextcontext) {
// get or create a cloudwatch log stream with uniqueLogIdreturn"hello world";
}
}In order to avoid these bugs we recommend writing your Lambda function’s code like below:
importcom.amazonaws.services.lambda.runtime.Context;
importcom.amazonaws.services.lambda.runtime.RequestHandler;
importjava.util.UUID;
publicclassLambdaLoggerimplementsRequestHandler<String, String> {
privateUUIDuniqueLogId;
@OverridepublicStringhandleRequest(Stringevent, Contextcontext) {
if (uniqueLogId == null) {
uniqueLogId = UUID.randomUUID();
}
// get or create a cloudwatch log stream with uniqueLogIdreturn"hello world";
}
}Lambda functions may capture execution environment creation time for various purposes. In this case the time value that initializes a Lambda function’s class member will have the time when snapshot is created.
importcom.amazonaws.services.lambda.runtime.Context;
importcom.amazonaws.services.lambda.runtime.RequestHandler;
publicclassLambdaUsingTimestampimplementsRequestHandler<String, String> {
privatelongenvCreationTime;
publicLambdaUsingUUID() {
// This is snapshotted by SnapStart, so it's a bugenvCreationTime = System.currentTimeMillis();
}
@OverridepublicStringhandleRequest(Stringevent, Contextcontext) {
// use envCreationTime to calculate the time differencereturn"hello world";
}
}You can eliminate this timing error by initializing the timestamp during snapshot resume as below.
importcom.amazonaws.services.lambda.runtime.Context;
importcom.amazonaws.services.lambda.runtime.RequestHandler;
importorg.crac.Resource;
publicclassLambdaUsingTimestampimplementsRequestHandler<String, String>, Resource {
privatelongenvCreationTime;
@OverridepublicvoidafterRestore(org.crac.Context<? extendsResource> context) {
envCreationTime = System.currentTimeMillis();
}
@OverridepublicStringhandleRequest(Stringevent, Contextcontext) {
// use envCreationTime to calculate the time differencereturn"hello world";
}
}