Buenas Practicas creando AWS Lambdas con Java

En esta entrada recopilaré buenas practicas que he aprendido al momento de crear Lambdas en AWS con Java y Maven. Algunas son mis recomendaciones y otras son desde AWS (sobre todo como evitar el cold start). Comenzamos:

  • Todo lo que pueda ser estático tiene que ser estático, de esta manera serán reutilizados en los siguientes request que se realicen en la misma instancia del Lambda.
  • inicializar todo lo que puedan en el handler del lambda en un bloque estático: 
    public class LambdaHandler implements RequestStreamHandler {
     
      static {
         // acá
      }
    
      @Override
      public void handleRequest(InputStream is, OutputStream os, Context ctx) throws IOException {
    
      }
    }
    Hay que hacer esto porque cuando se instancia la clase hay más poder de computo que el configurado como límite para la lambda, si hay conexiones a DynamoDB hay que instanciar la conexión y hacer una Query (cualquiera) lo importante es que se instancien todas las dependencias. Lo mismo ocurre para conexiones con RDS o cualquier otro recurso.
  • Utilizar CloudFormation o Serverless para automatizar nuestra solución.
  • No ocupar el plugin shade de maven para crear el Jar (no me gusta 😊), prefiero dejar dentro del jar una carpeta lib con todas las librerías la cual quedará disponible cuando se ejecute en el entorno de AWS:
    <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-dependency-plugin</artifactId>
       <version>3.1.1</version>
       <executions>
          <execution>
             <id>copy-dependencies</id>
             <phase>prepare-package</phase>
             <goals>
                <goal>copy-dependencies</goal>
             </goals>
             <configuration>
                <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
                <includeScope>runtime</includeScope>
             </configuration>
          </execution>
       </executions>
    </plugin>
  • Utilizar el logger de log4j por su versatilidad:
    <dependencies>
       <dependency>
          <groupId>com.amazonaws</groupId>
          <artifactId>aws-lambda-java-log4j2</artifactId>
          <version>1.1.0</version>
       </dependency>
       <dependency>
          <groupId>org.apache.logging.log4j</groupId>
          <artifactId>log4j-core</artifactId>
          <version>2.12.1</version>
       </dependency>
       <dependency>
          <groupId>org.apache.logging.log4j</groupId>
          <artifactId>log4j-api</artifactId>
          <version>2.12.1</version>
       </dependency>
    </dependencies>
    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration packages="com.amazonaws.services.lambda.runtime.log4j2">
       <Appenders>
          <Lambda name="Lambda">
             <PatternLayout>
                <pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1}:%L - %m%n</pattern>
             </PatternLayout>
          </Lambda>
       </Appenders>
       <Loggers>
          <Root level="info">
             <AppenderRef ref="Lambda" />
          </Root>
       </Loggers>
    </Configuration>
    private static final Logger LOGGER = LogManager.getLogger(LambdaHandler.class);
  • Usar sam para ejecuciones locales del lambda:
    sam local invoke NombreFuncion -t src/main/aws/template.yml
  • Para testing usar testcontainers con localstack, tendremos los servicios de AWS en nuestro ambiente de pruebas (es genial 😍):
       <dependency>
          <groupId>org.testcontainers</groupId>
          <artifactId>testcontainers</artifactId>
          <version>${test.containers}</version>
          <scope>test</scope>
       </dependency>
       <dependency>
          <groupId>org.testcontainers</groupId>
          <artifactId>localstack</artifactId>
          <version>${test.containers}</version>
          <scope>test</scope>
       </dependency>
  • No usar frameworks somo spring, jersey o similares, no es necesario (salvo que quieran utilizar graalvm para compilarlos), las lambdas deberían ser simples (muy personal, nada en contra de los frameworks)
El código de ejemplo está en Github 😇

No hay comentarios.:

Publicar un comentario