Задачи по расписанию
Некоторую работу приложение должно делать само, без запроса: раз в минуту собирать статистику, ночью чистить старые черновики, каждый час отправлять сводку. Для этого в Micronaut есть аннотация @Scheduled. Метод с ней фреймворк запускает в отдельном пуле потоков по расписанию. Ничего подключать не нужно — планировщик входит в ядро.
Первая задача
Создайте класс вручную или командой mn create-job com.example.StatsJob:
// src/main/java/com/example/StatsJob.java
package com.example;
import io.micronaut.scheduling.annotation.Scheduled;
import jakarta.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class StatsJob {
private static final Logger LOG = LoggerFactory.getLogger(StatsJob.class);
private final ArticleRepository articleRepository;
public StatsJob(ArticleRepository articleRepository) {
this.articleRepository = articleRepository;
}
@Scheduled(fixedDelay = "${blog.stats-interval:1m}", initialDelay = "5s")
void logStats() {
LOG.info("Статей в блоге: {}", articleRepository.count());
}
}Задача — обычный бин: она получает репозиторий через конструктор. initialDelay = "5s" — первый запуск через 5 секунд после старта, дальше пауза из настройки blog.stats-interval, а если её нет — одна минута. Длительности пишутся как 10s, 1m, 2h.
Проверка
Для наглядности сократите интервал в application.properties:
# src/main/resources/application.properties
blog.stats-interval=10sЗапустите приложение, создайте статью и посмотрите в журнал:
12:10:52.113 [scheduled-executor-thread-1] INFO com.example.StatsJob - Статей в блоге: 1
12:11:02.114 [scheduled-executor-thread-2] INFO com.example.StatsJob - Статей в блоге: 1Записи появляются каждые 10 секунд. Имя потока scheduled-executor-thread показывает, что задача выполняется не в потоке HTTP-запросов.
Виды расписаний
| Параметр | Как работает |
|---|---|
fixedDelay = "1m" | Пауза 1 минута после окончания предыдущего запуска |
fixedRate = "1m" | Запуск каждую минуту от начала предыдущего |
cron = "0 0 3 * * *" | По cron-выражению: каждый день в 03:00 |
initialDelay = "5s" | Задержка перед первым запуском |
Cron-выражение в Micronaut состоит из шести полей: секунды, минуты, часы, день месяца, месяц, день недели. Ночная задача выглядит так:
// src/main/java/com/example/StatsJob.java
@Scheduled(cron = "0 0 3 * * *")
void nightly() {
LOG.info("Ночная уборка");
}Если задача может длиться дольше интервала, выбирайте fixedDelay: запуски не наложатся друг на друга.
Частая ошибка
Метод с @Scheduled выполняется, только если его класс — бин. Если забыть @Singleton, приложение запустится без ошибок и предупреждений, но задача не будет работать ни разу — в журнале просто не появятся её записи. Когда задача «молчит», первым делом проверьте аннотацию области видимости на классе.