This Lambda code shows how AWS reuses the same environment context between several Java Lambda executions1. Especially, this demonstrates how the function handler is invoked from the same Singleton instance every time - until AWS reclaims the Lambda.
My definition of a 'Lambda execution context' is the following:
- the container running the Lambda
- the JVM running the Lambda
- the instance of the class where the handler is attached (a singleton)
In the AWS Lambda documentation, one of the best practice recommends to take advantage of this execution context:
Take advantage of Execution Context reuse to improve the performance of your function. Make sure any externalized configuration or dependencies that your code retrieves are stored and referenced locally after initial execution. Limit the re-initialization of variables/objects on every invocation. Instead use static initialization/constructor, global/static variables and singletons. Keep alive and reuse connections (HTTP, database, etc.) that were established during a previous invocation.
Unfortunately, the use static initialization/constructor, global/static variables and singletons
part is confusing.
I don't think they should have mentioned the use of static initialization
as a best practice, but instead it should be emphasized that the class where the handler method is running is itself a singleton.
Using static initializers decrease the testability of the code while not providing any benefit.
- AWS CLI already configured
- Java SE Development Kit 8 installed
- Docker installed
- Maven
- AWS SAM CLI installed
We use maven
to install our dependencies and package our application into a JAR file:
mvn package
Firstly, we need a S3 bucket
where we can upload our Lambda functions packaged as ZIP before we deploy anything - If you don't have a S3 bucket to store code artifacts then this is a good time to create one:
aws s3 mb s3://BUCKET_NAME
Next, run the following command to package our Lambda function to S3:
sam package \
--template-file template.yaml \
--output-template-file packaged.yaml \
--s3-bucket REPLACE_THIS_WITH_YOUR_S3_BUCKET_NAME
Next, the following command will create a Cloudformation Stack and deploy your SAM resources.
sam deploy \
--template-file packaged.yaml \
--stack-name lambda-handler \
--capabilities CAPABILITY_IAM
After deployment is complete you can run the following command to retrieve the API Gateway Endpoint URL:
aws cloudformation describe-stacks \
--stack-name lambda-handler \
--query 'Stacks[].Outputs[1].OutputValue'
Navigate to the url a few times. You will notice that not all the random number change after each invocation:
- The static number is evaluated only once for this Lambda instance
- The number initialized in the constructor is also evaluated only once
- The number generated in the handler is generated every time.
This is because AWS reuses the environment context to run the same instance of a Lambda (most of the time). The class holding the handler function is a Singleton and its instance is reused between invocation.
If this Lambda api was called multiple times and in parallel you would noticed that AWS starts other environment contexts to run the invocations in parallel.
Footnotes
-
AWS does not provide any guarantee to reuse the same execution context between invocations, but it is generally admitted than any sequential invocation of the Lambda will reuse the same context. That until the function is not invoked anymore and AWS reclaims the context. ↩