Build a native AWS Lambda with Java (GraalVM + AWS Lambda + Micronaut 4 - SQS Queue Trigger) In this article, we will be building a similar Lambda to the one in GraalVM with AWS Lambda - Starter To summarize the previous article, we manually:
created a custom runtime for the lambda
created a graalvm build environment on AL2 with Docker
packaged the lambda as zip on the pipeline
With the help of the Micronaut v4.2 framework that has excellent support for AWS Lambda, we will be achieving the same goal with the framework´s provided tooling.
Requirements You will need for this tutorial :
jdk 17
Micronaut cli (optional)
Docker
gradle / maven
Generate a project With the help of the Micronaut Launch page or the Micronaut CLI, you can easily generate a skeleton for your Aws Lambda.
On the Launch page:
or via MN CLI:
mn create-function-app --build=gradle_kotlin --jdk=17 --lang=java --test=junit --features=aws-lambda,aws-lambda-events-serde,aws-lambda-custom-runtime,graalvm com.example.demo
Make sure you include Micronaut Serialization libraries to be able to Serialize/Deserialize AWS Events
In this case, to be able to deserialize SQSEvent that we are receiving from the queue, we need
annotationProcessor("io.micronaut.serde:micronaut-serde-processor")
implementation("io.micronaut.aws:micronaut-aws-lambda-events-serde")
implementation("io.micronaut.serde:micronaut-serde-jackson")
Reference
https://micronaut-projects.github.io/micronaut-serialization/latest/guide/
https://micronaut-projects.github.io/micronaut-aws/latest/guide/#eventsLambdaSerde
Tailor the generated lambda to SQS Queue trigger / SQS Event Consumption The CLI generates a project with the structure:
By default, the Launcher generates a Lambda for API Proxy Gateway event. let´s adapt for SQS Events:
FunctionLambdaRuntime.java
package mn.aws.lambda.s3;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.function.aws.runtime.AbstractMicronautLambdaRuntime;
import java.net.MalformedURLException;
public class FunctionLambdaRuntime extends AbstractMicronautLambdaRuntime<SQSEvent, Void, SQSEvent, Void> {
public static void main(String[] args) {
try {
new FunctionLambdaRuntime().run(args);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
@Override
@Nullable
protected RequestHandler<SQSEvent, Void> createRequestHandler(String... args) {
return new FunctionRequestHandler();
}
}
FunctionRequestHandler.java
package mn.aws.lambda.s3;
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
import io.micronaut.core.annotation.Introspected;
import io.micronaut.function.aws.MicronautRequestHandler;
@Introspected
public class FunctionRequestHandler extends MicronautRequestHandler<SQSEvent, Void> {
@Override
public Void execute(SQSEvent input) {
System.out.println(" EVENT RECEIVED - IA - " + input.getRecords().get(0).getBody());
return null;
}
}
Build Thanks to Micronaut, this step is now as easy as:
gradle buildNativeLambda
it will start a build environment in docker with graalvm on AL2 and generate a zip for you!
Output with the native image and custom bootstrap for the Lambda:
Don´t mind my package names that says s3
I initially started with an S3NotificationEvent Lambda that I adapted for SQS
I first generated code with MN CLI mn create-aws-lambda
wizard
:)
Deploy Once the build finishes, set up your lambda as follows:
Set Runtime to "custom runtime with Amazon Linux 2"
Set handler to your own implementation FunctionRequestHandler
upload the zip:
Upload the zip that gradle generated under :
build/libs/mn-aws-lambda-s3-0.1-lambda.zip
Test Let´s run a test once your artefact uploaded:
Provide a name for your event
Choose the SQS Template since we set the serialization for this format
hit Test
There you go, you just built a native lambda with Java, thanks to Micronaut and GraalVM :)
Result:
The focus for this article is to get a working snippet for SQS Event consumption using Micronaut and GraalVM to get the most from native image support
This article doesn´t cover proper permission setup for SQS event consumption
Your Lambda needs proper roles setup to consume from your queue
In my case, I had to grant extra permissions to the lambda:
{
"Statement": [
{
"Action": [
"sqs:ReceiveMessage",
"sqs:GetQueueAttributes",
"sqs:DeleteMessage"
],
"Effect": "Allow",
"Resource": "arn:aws:sqs:eu-east-1:*****************",
"Sid": "SQSQueueAccess"
},
{
"Action": "kms:Decrypt",
"Effect": "Allow",
"Resource": "arn:aws:kms:eu-east-1:*****************",
"Sid": "SQSDecryptMessage"
}
],
"Version": "2022-10-17"
}
Last modified: 12 March 2024