Micronaut® Blog

Micronaut 2: AWS Lambda Functions

By Sergio del Amo

August 31, 2020

Tags: #aws #micronaut2

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 Application or Serverless Function. Those application types have their CLI-equivalent commands.

Application TypeCLI Command
Applicationcreate-app
Serverless Functioncreate-function-app

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.

Select Java 11 Corretto Runtime

Select Custom Runtime

Application Type, Runtime, and Dependencies

Depending on your application type and runtime, you need different dependencies:

Application TypeAWS Lambda RuntimeArtifactId
ApplicationJava 8/11micronaut-function-aws-api-proxy
ApplicationGraalVM Native Image in a AWS Lambda Custom Runtimemicronaut-function-aws-api-proxy, micronaut-function-aws-custom-runtime
Serverless FunctionJava 8/ 11micronaut-function-aws
Serverless FunctionGraalVM Native Image in a AWS Lambda Custom Runtimemicronaut-function-aws, micronaut-function-aws-custom-runtime

micronaut-function-aws-api-proxy has a transitive dependency to micronaut-function-aws.

The previous set of artifacts have a group id of io.micronaut.aws.

Micronaut CLI or Launch will include the necessary dependencies when you select the aws-lambda feature or both aws-lambda and graalvm features.

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 Application or Serverless Function. For other triggers, such as consuming events from a queue or running on a schedule, choose Serverless Function.

Application TypeTrigger type
Application or Serverless FunctionHTTP requests to a single endpoint
ApplicationHTTP requests to multiple endpoints
Serverless FunctionS3 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.

Handlers

AWS Lambda Function Handler

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 TypeAWS Handler InterfaceMicronaut Handler Class
Serverless FunctionRequestHandlerMicronautRequestHandler
Serverless FunctionRequestStreamHandlerMicronautRequestStreamHandler
ApplicationRequestStreamHandler < AwsProxyRequest , AwsProxyResponse >MicronautLambdaHandler

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 MicronautRequestHandler or 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 TypesHandler
Supply generic types with the input and outputClass which extends MicronautRequestHandler
Raw streamsMicronautRequestStreamHandler

Cold Startups

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

GraalVM is a universal virtual machine that allows you to compile Java programs to native executables.

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's dependency 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 aws-lambda and 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.

Next Steps

We have written several step-by-step tutorials to get you started:

Application TypeRuntimeTutorial
ApplicationJava 11Deploy a Micronaut application to AWS Lambda Java 11 Runtime JAVA KOTLIN GROOVY
ApplicationGraalVM Native Image Custom RuntimeDeploy a Micronaut application as a GraalVM Native Image to AWS Lambda JAVA KOTLIN
Serverless FunctionJava 11Deploy a Serverless Micronaut function to AWS Lambda Java 11 Runtime JAVA KOTLIN GROOVY
Serverless FunctionGraalVM Native Image Custom RuntimeDeploy a Serverless Micronaut function as a GraalVM Native Image to AWS Lambda JAVA

Check the Micronaut AWS documentation to learn more.