Codersrank - TOP DEVELOPERS IN JAVA

Hoy solo quiero dejar las capturas de pantalla de Codersrank en las cuales tengo el agrado de aparecer 😊, no se por cuanto tiempo estaré en el ranking, así que las guardo de recuerdo 😊.


  • Filtro: Chile + Santiago + Java = 1


  • Filtro: Chile + Java = 6





















llegar al 1 en Chile será un poco dificil...



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 😇

Java + Cognito: Pre Token Generation Lambda Trigger

En esta ocasión dejaré el código necesario para poder generar la respuesta en un Lambda de AWS que se ejecute como un Pre Token Generation Lambda Trigger, no es ninguna explicación de que es Lambda o Cognito, lo hago porque no encontré en el universo un ejemplo que explicara el formato de la respuesta usando Java, usando NodeJS habían cientos incluso desde la misma documentación de AWS...

Si alguien pasa por el mismo problema y llega acá, este es el código:

public class PreTokenGenerationLambdaTrigger implements RequestStreamHandler {
  private static final ObjectMapper OM;

  static {
    OM = new ObjectMapper();
    OM.enable(SerializationFeature.INDENT_OUTPUT);
    ServiceLoader.load(LambdaServicio.class).forEach(LambdaServicio::cargar);
  }

  @Override
  public void handleRequest(InputStream is, OutputStream os, Context ctx) throws IOException {
    final var request = OM.readTree(is);
    final var response = (ObjectNode) request;
    OM.writeValue(os, response); 
  }

}
El problema se solucionó con lo siguiente:
OM.enable(SerializationFeature.INDENT_OUTPUT);
Cognito reclamaba que no entendía la salida generada desde el Lambda, y con esa opción de Jackson se corrige. Ahora se pueden agregar atributos personalizados antes de generar el Token 😏