使用cron在Spring中安排周期性的反应任务?

Posted

技术标签:

【中文标题】使用cron在Spring中安排周期性的反应任务?【英文标题】:Scheduling periodic reactive tasks in Spring using cron? 【发布时间】:2019-05-19 00:49:48 【问题描述】:

通常我会做这样的事情来安排一个作业在 Spring 中定期执行,并在给定的时区使用 cron:

@Scheduled(cron = "0 0 10 * * *", zone = "Europe/Stockholm")
public void scheduleStuff() 
    // Do stuff

这将阻塞调用scheduleStuff 的线程,直到作业完成。但是在这种情况下,我想做的“东西”都是使用 Springs 的project reactor 的非阻塞构建块(即MonoFlux 等)实现的。

例如假设我想定期触发这个功能:

Flux<Void> stuff() 
    return ..

我当然可以简单地调用stuff().subscribe()(甚至stuff().block()),但这会阻塞线程。对于非阻塞代码,有没有更好的方法来实现与@Scheduled(cron = "0 0 10 * * *", zone = "Europe/Stockholm") 相同的功能?

我使用的是 Spring Boot 2.1。

【问题讨论】:

实际上,subscribe() 不会阻止您的线程。如果你真的需要,你可以调用stuff().subscribeOn(Schedulers.parallel()).subscribe() 或其他调度程序来确保执行将在一个单独的线程中完成。 @AlexanderPankin 我相信你可以这样回答 【参考方案1】:

实际上,subscribe() 不会阻塞您的线程。如果您确实需要,您可以调用stuff().subscribeOn(Schedulers.parallel()).subscribe() 或其他调度程序以确保执行将在单独的线程中完成。

【讨论】:

【参考方案2】:

您可以将 stuff 方法包装在异步方法中

例如:

@Scheduled(cron = "0 0 10 * * *", zone = "Europe/Stockholm")
public void scheduleStuff() 
    stuffService.doStuffAsync();

使用异步方法的服务

public class StuffService() implements IStuffService 

    @Async
    public void doStuffAsync() 
       // Call and subscribe to your flux method here
    


doStuffAsync() 的调用将立即返回scheduleStuff,因此不会阻塞线程。

【讨论】:

@BrianClozel 我没有遵循你的逻辑。 doStuffAsync() 将调用并订阅 stuff() 方法。这与接受的答案建议的相同。【参考方案3】:

这里还有一个选项:

public class PeriodicReactiveTasksInSpring implements SmartLifecycle 

    private final AtomicReference<Subscription> subscription;
    private final Long executionPeriod;

    public PeriodicReactiveTasksInSpring(Long executionPeriod) 
        this.subscription = new AtomicReference<>();
        this.executionPeriod = executionPeriod;
    

    @Override
    public void start() 
        if (Objects.isNull(subscription.get())) 
            updateConfig()
                    .doOnSubscribe(sub -> 
                        subscription.set(sub);
                    ).subscribe();
        
    

    @Override
    public void stop() 
        Optional.ofNullable(subscription.get())
                .ifPresent(sub -> 
                    sub.cancel();
                    subscription.set(null);
                );
    

    @Override
    public boolean isRunning() 
        return Objects.nonNull(subscription.get());
    


    private Flux<Item> updateConfig() 
        return Flux.interval(Duration.ofMillis(executionPeriod))
                .subscribeOn(Schedulers.boundedElastic())
                .flatMap(cfg -> 
                    // Do your job here
                )
                .onErrorContinue((err, msg) -> LOGGER.error("Error:  message: ", err, msg));
    


【讨论】:

以上是关于使用cron在Spring中安排周期性的反应任务?的主要内容,如果未能解决你的问题,请参考以下文章

在 NodeJS 中安排一个异步函数

没有在Google App Engine中安排的Cron作业

在本机反应中安排本地通知不起作用

运行在Google应用引擎中安排的应用的最佳做法是什么?

如何在android中安排通知并在固定时间发送

linux crontab定时执行任务