You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Micronaut定时任务等待应用启动完成后再执行?

解决Micronaut定时任务提前执行问题

全局解决方案:代理调度器延迟任务启动

无需修改现有定时任务代码,通过自定义代理TaskScheduler,让所有定时任务等待应用完全启动(即输出指定启动日志的时刻)后再执行首次任务,后续按原配置周期运行。

步骤1:实现代理调度器

创建包装默认TaskScheduler的代理类,缓存启动完成前的任务,启动完成后统一执行:

import io.micronaut.context.annotation.Primary;
import io.micronaut.scheduling.TaskScheduler;
import jakarta.inject.Singleton;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledFuture;

@Singleton
@Primary
public class StartupAwareTaskScheduler implements TaskScheduler {

    private final TaskScheduler delegate;
    private final List<Runnable> pendingTasks = new ArrayList<>();
    private volatile boolean started = false;

    public StartupAwareTaskScheduler(TaskScheduler delegate) {
        this.delegate = delegate;
    }

    @Override
    public ScheduledFuture<?> schedule(Runnable command) {
        if (started) {
            return delegate.schedule(command);
        } else {
            pendingTasks.add(command);
            return () -> false;
        }
    }

    @Override
    public ScheduledFuture<?> schedule(Runnable command, Duration delay) {
        if (started) {
            return delegate.schedule(command, delay);
        } else {
            pendingTasks.add(() -> delegate.schedule(command, delay));
            return () -> false;
        }
    }

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, Duration initialDelay, Duration period) {
        if (started) {
            return delegate.scheduleAtFixedRate(command, initialDelay, period);
        } else {
            pendingTasks.add(() -> delegate.scheduleAtFixedRate(command, Duration.ZERO, period));
            return () -> false;
        }
    }

    @Override
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, Duration initialDelay, Duration delay) {
        if (started) {
            return delegate.scheduleWithFixedDelay(command, initialDelay, delay);
        } else {
            pendingTasks.add(() -> delegate.scheduleWithFixedDelay(command, Duration.ZERO, delay));
            return () -> false;
        }
    }

    public void start() {
        if (!started) {
            started = true;
            pendingTasks.forEach(Runnable::run);
            pendingTasks.clear();
        }
    }
}

步骤2:监听启动完成事件

创建事件监听器,在应用输出启动完成日志后,触发代理调度器执行缓存任务:

import io.micronaut.context.event.ApplicationEventListener;
import io.micronaut.runtime.server.event.ServerStartupEvent;
import jakarta.inject.Singleton;

@Singleton
public class StartupListener implements ApplicationEventListener<ServerStartupEvent> {

    private final StartupAwareTaskScheduler taskScheduler;

    public StartupListener(StartupAwareTaskScheduler taskScheduler) {
        this.taskScheduler = taskScheduler;
    }

    @Override
    public void onApplicationEvent(ServerStartupEvent event) {
        taskScheduler.start();
    }
}

说明

  • ServerStartupEvent是Micronaut在服务器完全启动、输出你指定的启动完成日志后发布的事件,完全匹配需求。
  • 代理调度器会自动缓存启动完成前的所有定时任务,启动后立即执行首次任务,后续按原@Scheduled注解配置的周期/延迟运行。
  • 无需修改任何现有定时任务代码,全局生效,避免开发者遗漏。

内容的提问来源于stack exchange,提问作者Zonko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 18:15:14