Desenvolvimento Back-end Java

Trabalhando com Scheduled Tasks no Spring Boot

Descubra o poder das Scheduled Tasks no Spring Boot. Aprenda a criar, configurar e aprimorar tarefas agendadas em Java com o Spring Framework.

há 5 meses 5 dias

Formação Desenvolvedor Java
Conheça a formação em detalhes

No vasto ecossistema do desenvolvimento Java, a estrutura do Spring Framework destaca-se como uma escolha primordial para a construção de aplicativos robustos e escaláveis. Dentro desse universo dinâmico, a gestão eficaz de tarefas agendadas desempenha um papel crucial na otimização do desempenho e na automação de processos essenciais. Neste contexto, o Spring Framework oferece um conjunto poderoso de ferramentas para lidar com essas tarefas programadas, por isso, veremos sobre as Scheduled Tasks no Spring Boot.

Criando o projeto

Para exemplificar o uso de Scheduled Tasks no Spring Boot nós precisamos criar um projeto Spring Boot, para isso vamos utilizar o Spring Initializr.

Print da págia do Spring Initializr com as informações para criar o projeto Spring a ser utilizado como exemplo no artigo.

Vamos criar um projeto com as configurações demonstradas acima. Utilizaremos o Maven como gerenciador de projeto, como linguagem usaremos o Java na versão 21, como método de empacotamento iremos utilizar o JAR e teremos como dependência apenas o Spring Web. Além disso, foi definido os seguintes metadados para o projeto:

  • GroupId: br.com.treinaweb
  • ArtifactId: scheduled-tasks
  • Package Name: br.com.treinaweb.scheduledtasks

Agora, basta clicar no botão “Generate” para baixar o projeto base e então abri-lo em um editor de código-fonte ou IDE.

Spring Framework - Fundamentos
Curso Spring Framework - Fundamentos
Conhecer o curso

Configurando o projeto

Para podermos utilizar Scheduled Tasks no Spring Boot, nós precisamos habilitar esse recurso em nossa aplicação. Para isso, nós utilizamos a anotação @EnableScheduling, vamos criar uma classe chamada SchedulingConfig com o seguinte conteúdo:

package br.com.treinaweb.scheduledtasks;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

@Configuration
@EnableScheduling
public class SchedulingConfig {
    
}

A classe SchedulingConfig possui as seguintes anotações:

  • @Configuration: indica que a classe é uma classe de configuração Spring. No contexto do Spring Framework, as classes de configuração são usadas para definir configurações específicas da aplicação.
  • @EnableScheduling: ativa o suporte a tarefas agendadas no contexto do Spring. Essa anotação permite que o Spring agende métodos para serem executados em intervalos específicos.

Criando tasks

Agora que nosso projeto está com o recurso de Scheduled Tasks habilitado nós podemos criar as nossas tarefas agendadas, para isso basta criar um método com a lógica da tarefa a se realizada e então anotar esse método com a anotação @Scheduled. Essa anotação recebe alguns parâmetros que irão controlar quando a tarefa em questão será executada.

Spring Framework - Spring Data JPA
Curso Spring Framework - Spring Data JPA
Conhecer o curso

Scheduled Tasks com Fixed Delay

Um dos parâmetros que podemos passar para a anotação Scheduled é o fixedDelay, esse parâmetro nós podemos passar um número que irá representar quanto tempo após a última execução da tarefa é que será realizada a próxima execução, lembrando que esse tempo deve ser passado em milissegundos. Vejamos o exemplo abaixo:

package br.com.treinaweb.scheduledtasks;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

@Configuration
@EnableScheduling
public class SchedulingConfig {

    private static final long FIXED_DELAY = 5 * 1000; // 5 segundos
    
    private final Logger logger = LoggerFactory.getLogger(SchedulingConfig.class);

    @Scheduled(fixedDelay = FIXED_DELAY)
    public void cancelOrderWithoutPayment() {
        // Lógica para cancelar pedidos sem pagamento
        logger.info("Executando tarefa agendada para cancelar pedidos sem pagamento");
    }
    
}

No exemplo acima foi criada um método chamado cancelOrderWithoutPayment que irá simular uma tarefa de cancelar pedidos sem pagamento dentro do nosso sistema, esse método não receber nenhum parâmetro e também não irá retornar nada. Além disso, o método foi anotado com a anotação @Scheduled e foi passado o parâmetro fixedDelay com o valor 5000, o que fará com que a tarefa seja executada cinco segundos após a última execução.

Ao executarmos o projeto teremos a seguinte saída no terminal:

...
2023-11-15T13:55:44.091-03:00  INFO 86405 --- [  restartedMain] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.15]
2023-11-15T13:55:44.126-03:00  INFO 86405 --- [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-11-15T13:55:44.127-03:00  INFO 86405 --- [  restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 621 ms
2023-11-15T13:55:44.335-03:00  INFO 86405 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2023-11-15T13:55:44.351-03:00  INFO 86405 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-11-15T13:55:44.358-03:00  INFO 86405 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento
2023-11-15T13:55:44.358-03:00  INFO 86405 --- [  restartedMain] b.c.t.s.ScheduledTasksApplication        : Started ScheduledTasksApplication in 1.121 seconds (process running for 1.358)
2023-11-15T13:55:49.358-03:00  INFO 86405 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento
2023-11-15T13:55:54.358-03:00  INFO 86405 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento
2023-11-15T13:55:59.359-03:00  INFO 86405 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento

Scheduled Tasks com Fixed Rate

Nós também podemos utilizar o parâmetro fixedRate, diferente do fixedDelay esse parâmetro não leva em consideração a última execução, ou seja, se definirmos um fixedRate de cinco segundos para a nossa tarefa e a mesma demorar três segundo para executar, a próxima execução será em apenas dois segundos, pois o tempo de execução anterior não é levado em consideração.

package br.com.treinaweb.scheduledtasks;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

@Configuration
@EnableScheduling
public class SchedulingConfig {

    private static final long FIXED_RATE = 5 * 1000; // 5 segundos
    
    private final Logger logger = LoggerFactory.getLogger(SchedulingConfig.class);

    @Scheduled(fixedRate = FIXED_RATE)
    public void cancelOrderWithoutPayment() {
        // Lógica para cancelar pedidos sem pagamento
        logger.info("Executando tarefa agendada para cancelar pedidos sem pagamento");
    }
    
}

Ao executarmos o projeto teremos uma saída bem semelhante a anterior, pois a nossa tarefa é bem simples e não demora quase nada para ser executada.

...
2023-11-15T14:06:49.722-03:00  INFO 91996 --- [  restartedMain] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.15]
2023-11-15T14:06:49.796-03:00  INFO 91996 --- [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-11-15T14:06:49.798-03:00  INFO 91996 --- [  restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1010 ms
2023-11-15T14:06:50.248-03:00  INFO 91996 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2023-11-15T14:06:50.265-03:00  INFO 91996 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-11-15T14:06:50.271-03:00  INFO 91996 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento
2023-11-15T14:06:50.272-03:00  INFO 91996 --- [  restartedMain] b.c.t.s.ScheduledTasksApplication        : Started ScheduledTasksApplication in 1.739 seconds (process running for 1.957)
2023-11-15T14:06:55.271-03:00  INFO 91996 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento
2023-11-15T14:07:00.271-03:00  INFO 91996 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento
2023-11-15T14:07:05.271-03:00  INFO 91996 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento

Spring Framework - Desenvolvimento de APIs REST
Curso Spring Framework - Desenvolvimento de APIs REST
Conhecer o curso

Scheduled Tasks com Cron Expressions

Também é possível configurarmos a execução de nossas tarefas utilizando Cron Expressions, o que nos dar uma maior flexibilidade que não seria possível de alcançar utilizando fixed delay e fixed rate.

Mas primeiramente precisamos entender o que é uma cron expression.

O que é uma Cron Expression?

Uma cron expression é uma string de texto utilizada para representar um conjunto de instruções de agendamento de tempo em sistemas operacionais Unix-like. Essa expressão é comumente usada para agendar a execução de tarefas automatizadas, como scripts, backups ou outras atividades recorrentes.

A expressão cron é composta por cinco campos separados por espaços em branco, representando diferentes aspectos do agendamento. Porém, o Spring utiliza uma versão própria da cron expression padrão do Unix, na versão do Spring nós temos seis campos ao invés de cinco e esses campos funcionam da seguinte forma:

┌───────────── segundo (0-59)
│ ┌───────────── minuto (0 - 59)
│ │ ┌───────────── hora (0 - 23)
│ │ │ ┌───────────── dia do mês (1 - 31)
│ │ │ │ ┌───────────── mês (1 - 12) (or JAN-DEC)
│ │ │ │ │ ┌───────────── dia da semana (0 - 7) (0 or 7 is Sunday, or MON-SUN)
│ │ │ │ │ │
│ │ │ │ │ │
* * * * * *

As seguintes regras se aplicam:

  • Um campo pode ser um asterisco (*), que sempre representa “primeiro-último”. Para os campos “dia do mês” ou “dia da semana”, um ponto de interrogação (?) pode ser usado em vez de um asterisco.
  • Intervalos de números são expressos por dois números separados por um hífen (-). O intervalo especificado é inclusivo. Após um intervalo (ou *) com /n, especifica o intervalo do valor do número através do intervalo.
  • Nomes em inglês também podem ser usados nos campos “mês” e “dia da semana”. Use as três primeiras letras do dia ou mês específico (maiúsculas ou minúsculas não importam).
  • Os campos “dia do mês” e “dia da semana” podem conter um caractere L, que representa “último” e tem um significado diferente em cada campo:
    • No campo “dia do mês”, L representa “o último dia do mês”. Se seguido por um deslocamento negativo (ou seja, L-n), significa “n-ésimo último dia do mês”. Se seguido por W (ou seja, LW), significa “o último dia útil do mês”.
    • No campo “dia da semana”, dL ou DDDL significa “o último dia da semana d (ou DDD) no mês”.
  • O campo “dia do mês” pode ser nW, que representa “o dia útil mais próximo ao dia do mês n”. Se n cair em um sábado, isso resulta na sexta-feira anterior. Se n cair em um domingo, isso resulta na segunda-feira seguinte, o que também acontece se n for 1 e cair em um sábado (ou seja, 1W significa “o primeiro dia útil do mês”).
  • O campo “dia da semana” pode ser d#n (ou DDD#n), que representa “o n-ésimo dia da semana d (ou DDD) no mês”.

Alguns exemplos de expressões:

  • “0 0 * * * “: o início de cada hora todos os dias.
  • “/10 * * * * *”: a cada dez segundos.
  • “0 0 8-10 * * *”: 8, 9 e 10 horas todos os dias.
  • “0 0 6,19 * * *”: 6:00 e 19:00 todos os dias.
  • “0 0/30 8-10 * * *”: 8:00, 8:30, 9:00, 9:30, 10:00 e 10:30 todos os dias.
  • “0 0 9-17 * * MON-FRI”: a cada hora, das nove às cinco, nos dias úteis.
  • “0 0 0 25 12 ?”: todo Dia de Natal à meia-noite.
  • “0 0 0 L * *”: último dia do mês à meia-noite.
  • “0 0 0 L-3 * *”: terceiro dia útil do mês à meia-noite.
  • “0 0 0 1W * *”: primeiro dia útil do mês à meia-noite.
  • “0 0 0 LW * *”: último dia útil do mês à meia-noite.
  • “0 0 0 * * 5L”: último sexta-feira do mês à meia-noite.
  • “0 0 0 * * THUL”: última quinta-feira do mês à meia-noite.
  • “0 0 0 ? * 5#2”: a segunda sexta-feira do mês à meia-noite.
  • “0 0 0 ? * MON#1”: a primeira segunda-feira do mês à meia-noite.

Utilizando Cron Expresisons

Agora que já sabemos o que é uma cron expression e como elas se comportam, vamos ver um exemplo de sua utilização com as Scheduled Tasks no Spring Boot:

package br.com.treinaweb.scheduledtasks;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

@Configuration
@EnableScheduling
public class SchedulingConfig {

    private static final String EVERY_FIVE_SECONDS = "*/5 * * * * *";
    
    private final Logger logger = LoggerFactory.getLogger(SchedulingConfig.class);

    @Scheduled(cron = EVERY_FIVE_SECONDS)
    public void cancelOrderWithoutPayment() {
        // Lógica para cancelar pedidos sem pagamento
        logger.info("Executando tarefa agendada para cancelar pedidos sem pagamento");
    }
    
}

Para utilizarmos uma cron expression, nós continuamos usando a anotação @Scheduled, mas agora passamos o paramétrio cron, nesse exemplo utilizamos a cron expression "*/5 * * * * *", que significa que a tarefa será executada a cada cinco segundos.

Ao executar o projeto veremos o seguinte log no terminal:

2023-11-15T14:48:50.715-03:00  INFO 111858 --- [  restartedMain] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.15]
2023-11-15T14:48:50.750-03:00  INFO 111858 --- [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-11-15T14:48:50.751-03:00  INFO 111858 --- [  restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 599 ms
2023-11-15T14:48:50.948-03:00  INFO 111858 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2023-11-15T14:48:50.963-03:00  INFO 111858 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-11-15T14:48:50.970-03:00  INFO 111858 --- [  restartedMain] b.c.t.s.ScheduledTasksApplication        : Started ScheduledTasksApplication in 1.114 seconds (process running for 1.355)
2023-11-15T14:48:55.001-03:00  INFO 111858 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento
2023-11-15T14:49:00.000-03:00  INFO 111858 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento
2023-11-15T14:49:05.000-03:00  INFO 111858 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento
2023-11-15T14:49:10.000-03:00  INFO 111858 --- [   scheduling-1] b.c.t.scheduledtasks.SchedulingConfig    : Executando tarefa agendada para cancelar pedidos sem pagamento

Conclusão

Em conclusão, exploramos a poderosa capacidade do Spring Framework para lidar com tarefas agendadas por meio do módulo de Scheduled Tasks no Spring Boot. Ao longo do artigo, criamos um projeto Spring Boot, configuramos as tarefas agendadas usando anotações como @EnableScheduling e @Scheduled, e exploramos diferentes estratégias de agendamento, como fixedDelay, fixedRate, e até mesmo Cron Expressions.

A gestão eficiente de tarefas agendadas é essencial para a automação de processos e otimização de desempenho em aplicações Java. O Spring Framework, com sua abordagem simples e flexível, oferece uma solução robusta para atender a essas necessidades. Ao empregar as técnicas apresentadas neste artigo, os desenvolvedores podem criar sistemas mais eficientes e automatizados, garantindo a execução de tarefas no momento adequado e melhorando a experiência geral do usuário.

Autor(a) do artigo

Cleyson Lima
Cleyson Lima

Professor, programador, fã de One Piece e finge saber cozinhar. Cleyson é graduando em Licenciatura em Informática pelo IFPI - Campus Teresina Zona Sul, nos anos de 2019 e 2020 esteve envolvido em vários projetos coordenados pela secretaria municipal de educação da cidade de Teresina, onde o foco era introduzir alunos da rede pública no mundo da programação e robótica. Hoje é instrutor dos cursos de Spring na TreinaWeb, mas diz que seu coração sempre pertencerá ao Python.

Todos os artigos

Artigos relacionados Ver todos