# Build a native AWS Lambda with Java (GraalVM + AWS Lambda + Micronaut 4 - SQS Queue Trigger)

> **TL;DR**
> Build and deploy a GraalVM native AWS Lambda in Java using Micronaut 4, triggered by SQS. Covers project generation, SQS handler setup, Docker-based native build, and Lambda deployment with the ZIP upload method.

In this article, we will be building a similar Lambda to the one in [GraalVM Lambda Guide](graalvm-lambda.html). To summarize the previous article, we manually:

1. created a custom runtime for the Lambda

2. created a GraalVM build environment on AL2 with Docker

3. packaged the Lambda as a 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](https://micronaut.io/launch/) or the Micronaut CLI, you can easily generate a skeleton for your AWS Lambda.

On the Launch page:

* Pick the Function "Application for Serverless" as the application type

* Add the features listed below

![micronaut-function.png](img/micronaut-function.png)

or via MN CLI:

```SHELL
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
```

> **Tip:**
> 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
>
>
>
>
> ```GRADLE
> annotationProcessor("io.micronaut.serde:micronaut-serde-processor")
> implementation("io.micronaut.aws:micronaut-aws-lambda-events-serde")
> implementation("io.micronaut.serde:micronaut-serde-jackson")
> ```

## Tailor the generated Lambda to SQS Queue trigger / SQS Event Consumption

The CLI generates a project with the structure:

![micronaut-structure.png](img/micronaut-structure.png)

By default, the Launcher generates a Lambda for API Proxy Gateway event. Let's adapt it for SQS Events:

`FunctionLambdaRuntime.java`

```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`

```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:

```SHELL
gradle buildNativeLambda
```

It will start a build environment in Docker with GraalVM on AL2 and generate a zip for you!

![gradle-build-lambda-zip.png](img/gradle-build-lambda-zip.png)

Output with the native image and custom bootstrap for the Lambda:

![lambda-micronaut-zip.png](img/lambda-micronaut-zip.png)

> **Tip:**
> Don't mind my package names that say 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.
>
>
>
> ![mn-wizard.png](img/mn-wizard.png)
>
> :)

## Deploy

Once the build finishes, set up your Lambda as follows:

1. Set Runtime to "custom runtime with Amazon Linux 2"

2. Set handler to your own implementation `FunctionRequestHandler`

![set-handler.png](img/set-handler.png)

3. Upload the zip:

Upload the zip that Gradle generated under:

```SHELL
build/libs/mn-aws-lambda-s3-0.1-lambda.zip
```

![upload-lambda.png](img/upload-lambda.png)

## Test

Let's run a test once your artifact is uploaded:

1. Provide a name for your event

2. Choose the SQS Template since we set the serialization for this format

3. Hit Test

![sqs-tst.png](img/sqs-tst.png)

There you go, you just built a native Lambda with Java, thanks to Micronaut and GraalVM :)

Result:

![running-micronaut-lambda.png](img/running-micronaut-lambda.png)

> **Tip:**
> 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 set up to consume from your queue. In my case, I had to grant extra permissions to the Lambda:
>
>
>
>
> ```JSON
> {
> "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"
> }
> ```

> **Tip:**
> References
>
>
>
> [Micronaut Serialization Guide](https://micronaut-projects.github.io/micronaut-serialization/latest/guide/)
>
>
>
> [Micronaut AWS Events Lambda Serialization Guide](https://micronaut-projects.github.io/micronaut-aws/latest/guide/#eventsLambdaSerde)

