Introducción a Spring Batch. Toma 1

1. ¿Qué es un proceso batch?

Un proceso batch es una tarea automática para procesar un gran de volumen de datos. Este proceso se puede ejecutar sin interacción humana y repetirse periódicamente.

Qué no es un proceso batch: no es una tarea programada (un cron). Es bastante común programar un proceso batch, pero no es necesario hacerlo.

2. ¿Qué debemos tener en cuenta con un proceso batch?

  • Transaccionalidad porque queremos hacer roll back cuando los datos han sido invalidados.
  • Tolerancia a fallos porque no queremos que la aplicación termine cuando ocurra una excepción.
  • Reintentos porque… sometimes shit happens.
  • Logs y estadísticas porque de vez en cundo necesitamos saber qué ocurre dentro del proceso batch.
  • Parada y arranque de los procesos batch.
  • Administración web porque mola.
  • Particionamiento porque el trabajo puede ser compartido entre diferentes máquinas.

Cada uno de estos aspectos será comentado más tarde. He preparado unos cuantos commits en un repo para repasar todos estos puntos mostrando las diferencias en el código.

3. Conceptos de Spring Batch

Spring Batch es un proyecto que nos proporciona un framework para desarrollar aplicaciones batch. Este proyecto tiene un largo recorrido y es el resultado de la contribución de varias empresas con mucha experiencia en procesamiento batch.

Jobs, Steps, ItemReader, ItemProcessor and ItemWriter:

Fuente: Spring Batch Reference Documentation https://docs.spring.io/spring-batch/trunk/reference/html/domain.html

En Spring Batch se ejecutan jobs que se dividen en steps. Cada step tiene un componente para obtener los objetos (ItemReader), otro para procesarlos (ItemProcessor) y uno más para persistirlos (ItemWriter). El componente de procesamiento de datos es opcional.

Normalmente necesitaremos una instancia de JobBuilderFactory para declarar el Job y un StepBuilderFactory  para declarar el Step. No hay problema, Spring nos proporciona ambas.

JobExecution y JobLauncher

Un job puede ejecutarse por una instancia de JobLauncher. Durante su ejecución la información es almacenada y compartida en el JobExecutionContext y el StepExecutionContext.

El JobLauncher devuelve un JobExecution que nos da información sobre la ejecución, como por ejemplo el resultado de la misma: COMPLETED, FAILED…

JobInstance, JobParameters y RunIdIncrementer

JobInstance es la combinación de un Job y sus JobParameters. Una de las reglas de Spring Batch es que no se puede volver a ejecutar un Job si su JobExecution tiene estado COMPLETED. Sin embargo, se puede utilizar un RunIdIncrementer para ejecutar el mismo job varias veces ya que éste modifica internamente sus parámetros.

JobRepository

Spring Batch gestiona por sí sólo una base de datos con información sobre la ejecución de los jobs instanciando un bean de JobRepository. Para ello sólo necesitamos declarar la dependencia de H2 en el entorno de desarrollo.

4. Requisitos mínimos para comprobar que todo esto funciona

  • Dependencia de Spring Boot Starter Batch (aquí es donde reside toda la magia).
  • Dependencia del driver de la base de datos.
  • Anotación @EnableBatchProcessing en la clase de configuración de Spring.
  • Bean que define del job.
  • Bean que define el step con una tarea que escriba un mensaje «Reading…». Cuando esa tarea devuelva un null indicará el fin de la fuente de datos y por tanto que el job ha terminado.
@Bean
public Job job(Step step1) throws Exception {
    return jobBuilderFactory.get("job1")
        .incrementer(new RunIdIncrementer())
        .start(step1)
        .build();
}

@Bean
public Step step1() {
    return stepBuilderFactory.get("step1")
        .tasklet(new Tasklet() {
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
                System.out.println("Reading...");
                return null;
            }
        })
        .build();
}

Puedes clonar el repo que he preparado para este post y ver el código añadido en el primer commit para ejecutar Spring Batch con lo mínimo necesario.

Este artículo es una traducción del que escribí hace unos meses en el blog de Fintonic Engineering.

Desactivar autoconfiguración de Mongo en tests de integración con Spring Boot

Puede interesar, escribiendo un test, querer levantar el contexto de Spring sin instanciar ciertos componentes como la capa de acceso a datos. De esta manera, se prueba cierta integración sin pasar horas definiendo mocks.

Spring Boot utiliza la propiedad spring.autoconfigure.exclude para excluir clases @Configuration y no instanciar los beans declarados en su interior. Se puede definir esta propiedad para desactivar la autoconfiguración de Spring Boot Data Mongo. Las clases que instancian los componentes necesarios para utilizar una base de datos Mongo son:

– org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration
– org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration

Se puede utilizar la anotación @TestPropertySource para inyectar las propiedades al contexto de Spring que se levanta al ejecutar el test con la anotación @SpringBootTest.

Por último, habría que inyectar un mock de mongoTemplate a los componentes que lo usen.

Y para muestra, un ejemplo insultántemente tonto:

@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(properties = "spring.autoconfigure.exclude=
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration")
public class DemoApplicationTests {

    @Configuration
    static class TestConfiguration {
        @MockBean private MongoTemplate mongoTemplate;
    }

    @Test
    public void integrationTestNotNeedingRepository() {
        Assert.assertTrue(true);
    }
}

La magia de Spring Tool Suite

Siguiendo mi entrada anterior en la que comentaba algunas de las características de Spring Boot que son pura magia, hoy quiero destacar algunas de las funcionalidades de Spring Tool Suite, la distribución de eclipse desarrollada para el ecosistema Spring.

En esta charla de la SpringOne llamada Next Level Spring Boot Tooling, los ponentes completan y corrigen una aplicación Spring Boot que posteriormente ejecutan en local y en la plataforma Cloud Foundry.

Entre otras características, destacan cómo Spring Tool Suite sugiere, tras escribir el operador new de Java, las implementaciones encontradas para el tipo de la referencia que precede en la sentencia.

Una de las correcciones incluida en las últimas versiones de STS ha sido la de permitir duplicar y alterar la configuración de una aplicación para poder ejecutar desde el IDE varias instancias de ésta y probar la capacidad de escalado horizontal del servicio. Configurando el puerto con 0, el framework Spring Boot asignará un puerto aleatorio (después de arrancar) para la instancia, permitiendo así arrancar varias. Esto es muy adecuado para llevar a cabo las pruebas aunque en un sistema con contenedores -si fuese el caso-, las instancias expondrían el mismo puerto y se ejecutarían en diferentes IPs.

Quizás en otros IDEs ya está disponible tras definir un campo de una clase la posibilidad de añadir -como quick fix- la anotación @Autowired, sin embargo merece la pena destacarlo porque es bastante útil por la cantidad de beans que se inyectan.

La segunda parte de la charla repasa la integración de la herramienta con el PaaS Cloud Foundry y describen varias características, entre ellas cómo, tras desplegar una aplicación en la nube y haber modificado varias veces la configuración de ésa, STS compara la configuración local y la remota mostrando las diferencias para que puedan ser modificadas y guardadas. Siempre, a la hora de desplegar una aplicación necesitamos cambiar una configuración en el último momento. Una gran funcionalidad muy útil e inteligente que nos proporciona el equipo de Spring Tool Suite.

Por último, muestran cómo depurar de una forma más sencilla el conjunto de la aplicación registrando una instancia local contra el discovery service en Cloud Foundry (Eureka, por ejemplo).

Estas han sido algunas de las bondades que me han impresionado de la magia de STS pero hay muchas más por descubrir en el vídeo.