////
This guide is maintained in the main Quarkus repository
and pull requests should be submitted there:
https://github.com/quarkusio/quarkus/tree/master/docs/src/main/asciidoc
////
= Quarkus - Amazon Lambda
:extension-status: preview

include::./attributes.adoc[]

The `quarkus-amazon-lambda` extension allows you to use Quarkus to build your Amazon Lambdas.
Your lambdas can use injection annotations from CDI or Spring and other Quarkus facilities as you need them.

Quarkus lambdas can be deployed using the Amazon Java Runtime, or you can build a native executable and use
Amazon's Custom Runtime if you want a smaller memory footprint and faster cold boot startup time.

include::./status-include.adoc[]

== Prerequisites

To complete this guide, you need:

* less than 30 minutes
* JDK 1.8 (AWS requires JDK 1.8)
* Apache Maven {maven-version}
* https://aws.amazon.com[An Amazon AWS account]
* https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html[AWS CLI]
* https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html[AWS SAM CLI], for local testing

== Getting Started

This guide walks you through generating an example Java project via a maven archetype and deploying it to AWS.

== Installing AWS bits

Installing all the AWS bits is probably the most difficult thing about this guide.  Make sure that you follow all the steps
for installing AWS CLI.

== Creating the Maven Deployment Project

Create the Quarkus AWS Lambda maven project using our Maven Archetype.


[source, subs=attributes+]
----
mvn archetype:generate \
       -DarchetypeGroupId=io.quarkus \
       -DarchetypeArtifactId=quarkus-amazon-lambda-archetype \
       -DarchetypeVersion={quarkus-version}
----

== Choose Your Lambda

The `quarkus-amazon-lambda` extension scans your project for a class that implements the Amazon `RequestHandler` interface.
It must find a class in your project that implements this interface or it will throw a build time failure.
If it finds more than one handler class, a build time exception will also be thrown.

Sometimes, though, you might have a few related lambdas that share code and creating multiple maven modules is just
an overhead you don't want to do.  The `quarkus-amazon-lambda` extension allows you to bundle multiple lambdas in one
project and use configuration or an environment variable to pick the handler you want to deploy.

The generated project has two lambdas within it.  One that is used and one that is unused.  If you open up
`src/main/resources/application.properties` you'll see this:

[source, subs=attributes+]
----
quarkus.lambda.handler=test
----

The `quarkus.lambda.handler` property tells Quarkus which lambda handler to deploy. This can be overridden
with an environment variable too.

If you look at the two generated handler classes in the project, you'll see that they are `@Named` differently.

[source, subs=attributes+]
----
@Named("test")
public class TestLambda implements RequestHandler<InputObject, OutputObject> {
}

@Named("unused")
public class UnusedLambda implements RequestHandler<InputObject, OutputObject> {
}
----

The CDI name of the handler class must match the value specified within the `quarkus.lambda.handler` property.


== Deploy to AWS Lambda Java Runtime

There are a few steps to get your lambda running on AWS.  The generated maven project contains a helpful script to
create, update, delete, and invoke your lambdas for pure Java and native deployments.

== Build and Deploy

Build the project using maven.

[source, subs=attributes+]
----
./mvnw clean install
----

This will compile and package your code.

== Create an Execution Role

View the https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-awscli.html[Getting Started Guide] for deploying
a lambda with AWS CLI.  Specifically, make sure you have created an `Execution Role`.  You will need to copy and
paste the `Role Arn` into the scripts generated by the maven archetype.  To use the provided scripts, you will either
need to define a `LAMBDA_ROLE_ARN` environment variable in your profile or define it prior to executing the scripts like
this:

[source]
----
LAMBDA_ROLE_ARN="arn:aws:iam::1234567890:role/lambda-role"
----

== Create the function

The `manage.sh` script is for managing your lambda using the AWS Lambda Java runtime.  This script is provided only for
your convenience. Examine the output of the `manage.sh` script if you want to learn what aws commands are executed
to create, delete, and update your lambdas.

`manage.sh` supports four operation:  `create`, `delete`, `update`, and `invoke`.  You can create your function using the following command:

[source, subs=attributes+]
----
sh manage.sh create
----

or if you do not have `LAMBDA_ROLE_ARN` already defined in this shell:

[source]
----
LAMBDA_ROLE_ARN="arn:aws:iam::1234567890:role/lambda-role" sh manage.sh create
----

WARNING: Do not change the handler switch.  This must be hardcoded to `io.quarkus.amazon.lambda.runtime.QuarkusStreamHandler::handleRequest`.  This
handler bootstraps Quarkus and wraps your actual handler so that injection can be performed.

If there are any problems creating the function, you must delete it with the `delete` function before re-running
the `create` command.

[source, subs=attributes+]
----
sh manage.sh delete
----

Commands may also be stacked:
[source, subs=attributes+]
----
sh manage.sh delete create
----

== Invoke the Lambda

Use the `invoke` command to invoke your function.

[source, subs=attributes+]
----
sh manage.sh invoke
----

The example lambda takes input passed in via the `--payload` switch which points to a json file
in the root directory of the project.  If you want to see the output of the lambda, open the `response.txt` file.
The lambda can also be invoked locally like this:

[source]
----
sam local invoke --template sam.jvm.yaml --event payload.json
----

If you are working with your native image build, simply replace the template name above with the native version.

== Update the Lambda

You can update the Java code as you see fit.  Once you've rebuilt, you can redeploy your lambda by executing the
`update` command.

[source, subs=attributes+]
----
sh manage.sh update
----

== Deploy to AWS Lambda Custom (native) Runtime

If you want a lower memory footprint and faster initialization times for your lambda, you can compile your Java
code to a native executable.  Just make sure to rebuild your project with the `-Pnative` switch.

[source, subs=attributes+]
----
mvn clean install -Pnative
----

If you are building on a non-linux system, you will need to also pass in a property instructing quarkus to use a docker build as Amazon
Lambda requires linux binaries.  You can do this by passing this property to your maven build:
`-Dnative-image.docker-build=true`.  This requires you to have docker installed locally, however.

[source, subs=attributes+]
----
./mvnw clean install -Pnative -Dnative-image.docker-build=true
----

Either of these commands will compile and create a native executable image.  It also generates a zip file `target/function.zip`.
This zip file contains your native executable image renamed to `bootstrap`.  This is a requirement of Amazon Lambda
Custom Runtime.



The instructions here are exactly as above with one change:  you'll need to add `native` as the first parameter to the
`manage.sh` script:

[source, subs=attributes+]
----
sh manage.sh native create
----

As above, commands can be stacked.  The only requirement is that `native` be the first parameter should you wish
to work with native image builds.  The script will take care of the rest of the details necessary to manage your native
image function deployments.

Examine the output of the `manage.sh` script if you want to learn what aws commands are executed
to create, delete, and update your lambdas.

One thing to note about the create command for native is that the `aws lambda create-function`
call must set a specific environment variable:

[source, subs=attributes+]
----
--environment 'Variables={DISABLE_SIGNAL_HANDLERS=true}'
----

== Examine the POM

If you want to adapt an existing project to use Quarkus's Amazon Lambda extension, there are a couple
of things you need to do.  Take a look at the generated example project to get an example of what you need to adapt.

1. Include the `quarkus-amazon-lambda` extension as a pom dependency
2. Configure Quarkus to build an `uber-jar` (via quarkus.package.uber-jar=true in the application.properties)
3. If you are doing a native image build, Amazon requires you to rename your executable to `bootstrap` and zip it up.
Notice that the `pom.xml` uses the `maven-assembly-plugin` to perform this requirement.

NB: With gradle, to build the uber-jar execute: ./gradlew quarkusBuild --uber-jar

== Testing with the SAM CLI

The https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html[AWS SAM CLI]
allows you to run your lambdas locally on your laptop in a simulated Lambda environment.  This requires
https://www.docker.com/products/docker-desktop[docker] to be installed.  This is an optional approach should you choose
to take advantage of it.  Otherwise, dev mode should be sufficient for most of your needs.

A starter template has been generated for both JVM and native execution modes.

Run the following SAM CLI command to locally test your lambda function:

[source]
----
sam local invoke --template sam.jvm.yaml --event {json test file}
----

The native image can also be locally tested using the `sam.native.yaml` template:

[source]
----
sam local invoke --template sam.native.yaml --event {json test file}
----

== Tracing with AWS XRay and GraalVM

If you are building native images, and want to use https://aws.amazon.com/xray[AWS X-Ray Tracing] with your lambda
you will need to include `quarkus-amazon-lambda-xray` as a dependency in your pom.  The AWS X-Ray
library is not fully compatible with GraalVM so we had to do some integration work to make this work.
