Micronaut 2: AWS Lambda Functions
August 31, 2020
Micronaut 2 includes many improvements to help you write Micronaut applications and serverless functions and deploy them to AWS Lambda.
Micronaut Application Types for AWS Lambda Functions
In Micronaut Launch, you can select the feature
aws-lambda for applications of type
Serverless Function. Those application types have their CLI-equivalent commands.
|Application Type||CLI Command|
AWS Lambda Considerations
To deploy an AWS Lambda function, you have to:
- Select a runtime
- Choose how your Lambda is triggered
- Specify your Handler
- Upload your code
The above decisions influence the type of Micronaut application you choose.
Select a Runtime
To deploy a Micronaut function to AWS Lambda, choose an AWS Lambda Runtime. For Micronaut functions, select a Java (8 or 11) or custom runtime. To deploy your Micronaut function as a GraalVM Native Image, select a custom runtime.
Application Type, Runtime, and Dependencies
Depending on your application type and runtime, you need different dependencies:
|Application Type||AWS Lambda Runtime||ArtifactId|
|Application||GraalVM Native Image in a AWS Lambda Custom Runtime|
|Serverless Function||Java 8/ 11|
|Serverless Function||GraalVM Native Image in a AWS Lambda Custom Runtime|
micronaut-function-aws-api-proxy has a transitive dependency to
The previous set of artifacts have a group id of
Micronaut CLI or Launch will include the necessary dependencies when you select the
aws-lambda feature or both
Choose How Your Lambda Is Triggered
AWS Lambda integrates with other AWS services to invoke functions. The Micronaut application type you select depends on the triggers you want to support. To respond to incoming HTTP requests (e.g. AWS Lambda Proxy integrations in API Gateway), you can choose either
Serverless Function. For other triggers, such as consuming events from a queue or running on a schedule, choose
|Application Type||Trigger type|
|HTTP requests to a single endpoint|
|HTTP requests to multiple endpoints|
|S3 events, events for a queue, schedule triggers etc.|
On the one hand, if you need to support a single endpoint, a
Serverless Function gives you a function with less code (which translates to a faster cold startup).
Functions written as an application of type
Application allow you to code with a more familiar paradigm — classes annotated with
@Controller. This is possible because, through the
micronaut-function-aws-api-proxy dependency, Micronaut integrates with the AWS Serverless Java Container project.
Your Lambda function's handler is the method in your function code that processes events. When your function is invoked, Lambda runs the handler method. When the handler exits or returns a response, it becomes available to handle another event.
The aws-lambda-java-core library defines two interfaces for handler methods. When coding your functions with Micronaut, you don't implement those interfaces directly. Instead, you extend or use its Micronaut equivalents:
|Application Type||AWS Handler Interface||Micronaut Handler Class|
For functions of type
Application, use the handler io.micronaut.function.aws.proxy.MicronautLambdaHandler.
To resolve that class, add the
micronaut-function-aws-api-proxy dependency to your build.
For Serverless Functions, the decision to use one
MicronautRequestStreamHandler depends on how you want to handle the input and output types.
To resolve those classes, add the
micronaut-function-aws dependency to your build.
With MicronautRequestHandler, it is expected that you supply generic types with the input and the output types. If you wish to work with raw streams, then subclass MicronautRequestStreamHandler instead.
|Input / Output Types||Handler|
|Supply generic types with the input and output||Class which extends MicronautRequestHandler|
Instances of Lambdas are added and removed dynamically. When a new instance handles its first request, the response time increases, which is called a cold start. After that request is processed, the instance stays alive (≈10 m) to be reused for subsequent requests.
Lambdas execution has different phases (initialization, invocation ...).
During the initialization phase:
- AWS Lambda starts a JVM.
- Java runtime loads and initializes handler class.
- Lambda calls the handler method.
The intialization phase has access to more CPU; because of that, Micronaut starts the application context and eagerly inits singletons during the intialization of the handler class.
GraalVM and AWS Custom Runtimes
The introduction of AWS Lambda custom runtimes enables cold startup improvements for Java applications running in AWS Lambda.
A runtime is a program that runs a Lambda function's handler method when the function is invoked. You can include a runtime in your function's deployment package in the form of an executable file named bootstrap.
micronaut-function-aws-custom-runtime eases the creation of AWS Lambda Custom runtime to execute a Micronaut function.
The main API you will interact with is AbstractMicronautLambdaRuntime. An abstract class that you can extend to create your custom runtime is
mainClass. That class includes the necessary code to perform the Processing Tasks described in the Custom Runtime documentation.
When you generate a project with Micronaut CLI or Micronaut Launch with
graalvm features, the output includes the necessary files to generate a ZIP file to distribute your functions as a GraalVM Native Image executed from a AWS Lambda custom runtime.
We have written several step-by-step tutorials to get you started:
|Application||Java 11||Deploy a Micronaut application to AWS Lambda Java 11 Runtime JAVA KOTLIN GROOVY|
|Application||GraalVM Native Image Custom Runtime||Deploy a Micronaut application as a GraalVM Native Image to AWS Lambda JAVA KOTLIN|
|Serverless Function||Java 11||Deploy a Serverless Micronaut function to AWS Lambda Java 11 Runtime JAVA KOTLIN GROOVY|
|Serverless Function||GraalVM Native Image Custom Runtime||Deploy a Serverless Micronaut function as a GraalVM Native Image to AWS Lambda JAVA|
Check the Micronaut AWS documentation to learn more.