En este artículo les voy a explicar como crear AWS Lambdas usando Quarkus. Pero primeramente debemos saber que AWS Lambda nos permite ejecutar código sin aprovisionar o manejar servidores, es decir es serverless. Por lo cual nos despreocupamos de todo lo que se necesita para que nuestro código ejecute y escale automáticamente en un entorno de alta disponibilidad.

Además, pagamos solo por el tiempo de computación que se consume, por lo cual es muy deseable que nuestro código sean tan rápido como sea posible, y es ahí donde hace mucho sentido usar Quarkus.

Las funciones en Lambda se pueden escribir en múltiples lenguajes, que a la fecha son:

  • .NET Core 3.1/2.1 (C#/PowerShell)
  • Go 1.x
  • Java 11/8
  • Node.js 12x/10x
  • Python 3.8/3.6/2.7
  • Ruby 2.7
  • Un runtime personalizado (he visto Perl funcionando así)

Dicho lo anterior, para este ejercicio vamos a usar Quarkus 1.3.1 el cual ya usa por omisión Java 11. Para crear el proyecto ejecutamos lo siguiente desde la terminal empleando el siguiente arquetipo.

Debo aclarar que la extensión de quarkus para Lambda esta en una fase de preview, pero yo la he usado sin ningún inconveniente en ambientes productivos. Pero si deben tener presente que la especificación puede cambiar entre releases de Quarkus.

mvn archetype:generate \
       -DarchetypeGroupId=io.quarkus \
       -DarchetypeArtifactId=quarkus-amazon-lambda-archetype \
       -DarchetypeVersion=1.3.1.Final

Por supuesto, también pueden generar lo anterior desde https://code.quarkus.io/ y seleccionar la extensión desde ahí y descargar el proyecto.

Generar

Una vez que generamos nuestro proyecto, observaremos que nos crea varias clases con código de ejemplo. Una de ellas se llama TestLambda. Esta posee el handler que se requiere para integrarnos al Lambda.

@Named("test")
public class TestLambda
       implements RequestHandler<InputObject, OutputObject> {

    @Inject
    ProcessingService service;

    @Override
    public OutputObject handleRequest(InputObject input,
                   Context context) {
        return service.process(input)
             .setRequestId(context.getAwsRequestId());
    }
}

Debemos notar varias cosas aquí:

  • La clase esta anotada con @Named y el nombre que indiquemos ahí debemos tenerlo presente para ajustar la propiedad quarkus.lambda.handler del archivo application.properties.
  • Implementa RequestHandler e indicamos la clase que representa la entrada/salida y que corresponde a un JSON.
  • Se puede hacer uso de CDI, como por ejemplo este @Inject de un servicio.
  • El método de interés es el handleRequest. El cual sobreescribimos con nuestra lógica. Este recibe como segundo parámetro el contexto de ejecución de AWS Lambda.

Ahora generemos el jar de nuevo primer lambda.

mvn clean package

Primero vamos a subir nuestra función por la consola de AWS y damos click en Create function. Debemos seleccionar el runtime de Java 11 y colocar un nombre adecuado para nuestra función. Es importante seleccionar el permiso adecuado o bien crear un rol básico, esto en la parte de permisos.

Creación

El siguiente paso involucra subir nuestro jar, es importante que el handler sea exactamente este: io.quarkus.amazon.lambda.runtime.QuarkusStreamHandler::handleRequest

Subir

Para probar nuestro código hacemos un test, el cual se hace en la parte superior del menu y debemos digitar lo siguiente:

Test

y cuyo resultado es:

Test

Observen que demoró 1.32 ms, nada mal.

Ahora, vamos a hacer un cambio y es genera una imagen nativa. Lo que debemos hacer es primero compilar nuestro proyecto como un ejecutable nativo. Es importante que tengas instalado GraalVM 19.3.1, docker y los prerequisitos indicados aquí.

mvn clean install -Pnative -Dnative-image.docker-build=true

Dado que esta prueba la hago en MacOS, necesito agregar la propiedad -Dnative-image.docker-build=true para indicarle a quarkus que use un build de docker, pues Amazon Lambda requiere de un binario linux.

El resultado es un archivo llamado function.zip en el directorio target. Este zip lo que tiene es el ejecutable renombrado a bootstrap; pues es un requerimiento de AWS Lambda.

Debemos actualizar nuestro lambda con este nuevo zip y seleccionar que el runtime es custom

custom

Luego debemos agregar una variable de ambiente DISABLE_SIGNAL_HANDLERS y que posea el valor true. Si no lo hacemos, tendremos un error de ejecución.

disable

Si repetimos nuestra pruebe tendremos un resultado satisfactorio y además, un excelente tiempo de arranque en frío.

resultado

Otra manera de crear, actualizar y eliminar nuestra función es usar el comando manage.sh que nos generó el arquetipo de maven. Les sugiero que lo revisen para que vean como funciona.

Conclusión


Espero que este artículo les impulse a usar Java en funciones Lambda de AWS, es bastante sencillo y tiene excelentes tiempos de ejecución gracias a Quarkus.