Programación de tareas de Spring Boot

     

    Introducción

    Programar tareas para que se realicen en una fecha posterior o se repitan en un intervalo fijo es una característica muy útil. Por ejemplo, los sistemas de boletines o las tareas que procesan información en un período de tiempo determinado dependen de que se programen para ejecutarse en determinados momentos.

    Dado que Spring Boot ofrece varias opciones, las cubriremos e implementaremos todas.

    Configuración del proyecto

    Como de costumbre, cuando se trata de construir aplicaciones Spring Boot, hacer un proyecto esqueleto es más fácil con la ayuda de Spring Initializr. No necesita ninguna dependencia adicional para habilitar la programación.

    Para habilitar la programación, todo lo que tenemos que hacer es anotar nuestra clase principal:

    @SpringBootApplication
    @EnableScheduling
    public class SampleScheduleApplication {
        public static void main(String[] args) {
            SpringApplication.run(SampleScheduleApplication.class, args);
        }
    }
    

    los @EnableScheduling La anotación permite que el contenedor Spring observe cualquier @Scheduled anotaciones en beans gestionados por Spring.

    Programación condicional

    Hay otra forma de habilitar la programación: mediante el @ConditionalOnProperty anotación. Nos permite “encender” y “apagar” nuestras clases de configuración estableciendo una propiedad en el application.properties clase.

    Para hacer esto, creemos una nueva clase y anotémosla con los @EnableScheduling, @Configuration y @ConditionalOnProperty anotaciones:

    @EnableScheduling
    @Configuration
    @ConditionalOnProperty(name = "spring.enable.scheduling")
    public class ScheduleEnabling {}
    

    Ahora, en el application.properties archivo, agreguemos nuestra nueva propiedad y configurémosla en true:

    spring.enable.scheduling = true
    

    Con solo cambiar esta variable, podemos activar y desactivar la funcionalidad.

    Para ejecutar un método en un horario, necesita anotarlo con el @Scheduled anotación. Cambiar los parámetros de la anotación definirá si es a una tasa fija, con un retraso fijo, intervalos personalizados, etc.

    Programación con FixedRate y FixedRateString

    Para programar un método para que se ejecute a una tasa fija, agregaremos el parámetro adecuado a nuestra anotación: @Scheduled(fixedRate). Este parámetro acepta enteros, expresados ​​en milisegundos. Entonces, si desea una tasa de 1 segundo, la tasa debe ingresarse como 1000 ya que el valor es milisegundos.

    Alternativamente, puede utilizar el @Scheduled(fixedRateString) parámetro para externalizar la cantidad utilizando una variable de cadena de entorno.

    Para evitar confusiones, iremos con el fixedRateString, que es esencialmente un parámetro de cadena que especifica la tasa, en lugar del valor entero. Puede resultar un poco complicado intentar que un método se repita mensualmente en milisegundos.

    Establezcamos una variable en el application.properties archivo:

    sample.schedule.string = PT2S
    

    El prefijo PT es el estándar ISO-8601 para anotando duraciones o períodos, y con esto, podemos llamar al sample.schedule.string para programar una llamada a un método en 2 segundos.

    Esto también nos permite especificar diferentes retrasos para diferentes perfiles en uso:

    @Scheduled(fixedRateString = "${sample.schedule.string}")
    public void scheduleTaskWithFixedRate() throws InterruptedException {
        task1();
        task2();
    }
    
    public void task1() throws InterruptedException {
        logger.info("Task 1 starts" + Thread.currentThread());
        Thread.sleep(1000);
        logger.info("Task 1 ends" + Thread.currentThread());
    }
    
    public void task2() throws InterruptedException {
        logger.info("Task 2 starts" + Thread.currentThread());
        Thread.sleep(1000);
        logger.info("Task 2 ends" + Thread.currentThread());
    }
    

    Ejecutemos este fragmento de código:

    Sin embargo, podemos ver un problema aquí:

    La tarea 1 comienza a las 00:01:44 y finaliza a las 00:01:45, como se esperaba.
    La tarea 2 comienza a las 00:01:45 y termina a las 00:01:46, como se esperaba.
    La tarea 1 comienza a las 00:01:46 y termina a las 00:01:47.

    Ya que ambos task1() y task2() se han ejecutado, esperaría que el método esperara 2 segundos adicionales para ejecutarse nuevamente.

    Las tareas de tasa fija no esperan la finalización de la ejecución anterior, simplemente invoca el método a una tasa específica. Dado que se necesitan 2 segundos para terminar los métodos task1() y task2(), el método se invoca nuevamente al mismo tiempo que estos dos terminan.

    Esto puede convertirse en un problema en un entorno con múltiples tareas programadas.

    Considera esto – task1() tarda 1 minuto en completarse, y task2() tarda 5 segundos en completarse. Dado que ambos se ejecutan en un solo hilo, puede haber una situación que task1() comienza a procesar y bloqueará el hilo. Esto no permitirá task2() procesar incluso si hay un fixedRate de 5 segundos.

    En este escenario, necesitamos aumentar la cantidad de subprocesos que están disponibles en nuestro grupo de subprocesos para la programación. Spring proporciona una propiedad que podemos manipular para especificar el tamaño: spring.task.scheduling.pool.size – el valor predeterminado es 1.

    Podemos usar una tasa fija cuando una tarea en particular debe realizarse repetidamente, pero cada tarea es independiente de la otra. Además, tenga cuidado de no tener tareas pesadas sin un ritmo adecuado, ya que las tareas incompletas pueden provocar una OutOfMemoryError.

    Programación con FixedDelay y FixedDelayString

    UN fixedDelay funciona muy similar a un fixedRate. Pero la diferencia aquí es que la demora fija espera hasta la finalización de la ejecución anterior para iniciar la siguiente. Imagine un escenario en el que su función tarda 1 segundo en completarse y le ha dado un retraso fijo de 2 segundos.

    Esto, a su vez, dará como resultado un total de 3 segundos.

    En los registros a continuación, puede ver claramente que la diferencia entre las dos tareas posteriores es de 3 segundos. Esto incluye el tiempo de retardo fijo de 1 segundo, así como los 2 segundos que hemos dado como suspensión:

    @Scheduled(fixedDelayString = "${sample.schedule.string}")
    public void scheduleTaskWithFixedDelay() throws InterruptedException {
        task1();
    }
    
    public void task1() throws InterruptedException {
        logger.info("Task 1 starts" + Thread.currentThread());
        Thread.sleep(1000);
        logger.info("Task 1 ends" + Thread.currentThread());
    }
    

    Ejecutemos este fragmento de código:

    Hay un parámetro adicional que se puede agregar a las tareas programadas, y es el initialDelay.

    Este no requiere mucha explicación ya que se usa junto con los dos anteriores. La demora inicial, como su nombre sugiere con razón, proporciona la demora inicial para la primera ejecución.

    Si tiene una función con un retraso inicial de 2 segundos y una frecuencia fija de 1 segundo, la primera ejecución se retrasará 2 segundos y la función se ejecutará cada segundo después:

    @Scheduled(initialDelay = 1000, fixedRateString = "${sample.schedule.string}")
    public void scheduleTaskWithInitialDelay() throws InterruptedException {
        task1();
    }
    

    También podemos optar por utilizar un initialDelayString que nos permite externalizar el valor de retardo.

    Intervalos de tiempo personalizados

    La tasa fija y el retardo fijo son los parámetros más utilizados para la programación y las cadenas de retardo nos permiten externalizar los valores y hacerlos configurables.

    Pero hasta ahora solo hemos visto ejemplos muy genéricos de tarifas. Puede haber una situación en la que necesitemos intervalos de tiempo muy específicos. He aquí, costumbre cron Expresiones

    Expresiones Cron

    La mayoría de los desarrolladores probablemente hayan oído hablar cron utilidad en Linux. Es un proceso demonio que se ejecuta sin la necesidad de la intervención del usuario y ejecuta tareas.

    La sintaxis de las expresiones cron en el cron La utilidad y la sintaxis de las expresiones cron para la programación son en su mayoría similares.

    Las expresiones cron son básicamente cadenas que describen los detalles del programa. Proporciona mucho más control que los 2 métodos anteriores:

    Nombre Requerido Valores permitidos Caracteres especiales permitidos

    Segundossi0-59, - * /
    Minutossi0-59, - * /
    Horassi0-23, - * /
    Dia del messi1-31, - * / L W C
    Messi0-11 o ENE-DIC, - * /
    Día de la semanasi1-7 o SUN-SAT, - * / L C #
    AñoNovacío o 1970-2099, - * /

    La tabla anterior especifica los valores requeridos, los valores permitidos y los caracteres especiales para una expresión cron.

    Las expresiones cron pueden ser muy simples, pero también muy complejas. Una comprensión clara de los valores hará que sea más fácil jugar con ellos.

    Excepto por el campo del año, todos los demás campos son obligatorios:

    <second> <minute> <hour> <day-of-month> <month> <day-of-week> <year>
    

    Ejemplo: 0 0 12 * * ? 2019 – Esta expresión cron se activa a las 12 p.m., todos los días del mes, para cada mes, para el año 2019.

    Para algunos valores comunes, también puede usar las anotaciones predefinidas:

    • @reboot: Programe el método para cada reinicio de la aplicación
    • @yearly/@anually: Programe el método para que se ejecute una vez al año
    • @monthly: Programe el método para que se ejecute una vez al mes
    • @weekly: Programe el método para que se ejecute una vez a la semana
    • @daily/@midnight: Programe el método para que se ejecute una vez al día
    • @hourly: Programe el método para que se ejecute una vez cada hora

    Escribamos un ejemplo de código para esto:

    @Scheduled(cron="0 0 12 * * ? 2019")
    public void doSomething() {
        // Something
    }
    

    Una cosa importante a tener en cuenta al programar son las zonas horarias, la pesadilla de todo desarrollador que trabaja con el tiempo.

    Es probable que desee configurar el zone bandera a una región específica. Por ejemplo, ejecutaremos este método a las 12 p.m., todos los días de 2019, según la zona horaria de París:

    @Scheduled(cron="0 0 12 * * ? 2019", zone="Europe/Paris")
    public void doSomething() {
        // Something
    }
    

    Puede encontrar todas las zonas horarias en la documentos oficiales de Oracle.

    Por supuesto, también puede externalizar expresiones cron a través del application.properties archivo:

    cron.expression= 0 0 12 * * ? 2019
    

    Y luego invocarlo a través de:

    @Scheduled(cron="${cron.expression}", zone="Europe/Paris")
    public void doSomething() {
        // Something
    }
    

    También puede utilizar un sitio como FreeFormatter para generar una expresión cron estableciendo los parámetros de entrada. Esto es muy útil para aquellos que son nuevos en la creación de expresiones cron.

    Conclusión

    En este artículo, hemos visto cómo podemos programar tareas con Spring Boot. La mayor ventaja de usar Spring Boot es la facilidad con la que podemos implementar la programación. No solo eso, también ofrece varias opciones para que podamos elegir la que se adapte a nuestras necesidades.

    Los programadores son componentes esenciales de la mayoría de las aplicaciones porque envían información de tiempo crítico y específica del usuario cuando es necesario. ¡Ahora sabes cómo!

    .

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *