停止春季计划执行,如果它在一些固定时间后挂起

2022-09-03 13:41:59

我使用Spring Framework来安排我的工作,使用cron每5分钟运行一次。但有时我的工作会无限等待外部资源,我无法将超时放在那里。我无法使用,因为以前的进程有时会进入无限等待模式,并且我必须每5分钟刷新一次数据。ScheduledfixedDelay

所以我在Spring Framework中寻找任何选项,以便在它成功运行或运行失败后停止该进程/线程。Scheduledfixed-time

我在下面找到了设置,该设置初始化为120秒,我将其放入课堂。谁能告诉我,这是否会像我预期的那样工作。ThreadPoolExecutorkeepAliveTime@Configuration

@Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
    int coreThreads = 8;
    int maxThreads = 20;
    final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            coreThreads, maxThreads, 120L, 
            TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()
    );
    threadPoolExecutor.allowCoreThreadTimeOut(true);

    return threadPoolExecutor;
}

答案 1

我不确定这会按预期工作。实际上,keepAlive是针对IDLE线程的,我不知道等待资源的线程是否处于IDLE状态。此外,只有当线程数大于内核时,否则除非您监视线程池,否则您无法真正知道何时发生。

keepAliveTime - 当线程数大于内核时,这是多余的空闲线程在终止之前等待新任务的最长时间。

您可以执行以下操作:

public class MyTask {

    private final long timeout;

    public MyTask(long timeout) {
        this.timeout = timeout;
    }

    @Scheduled(cron = "")
    public void cronTask() {
        Future<Object> result = doSomething();
        result.get(timeout, TimeUnit.MILLISECONDS);
    }

    @Async
    Future<Object> doSomething() {
        //what i should do
        //get ressources etc...
    }
}

不要忘记添加@EnableAsync

也可以通过实现可调用来执行相同的操作。@Async

编辑:请记住,它将等到超时,但运行任务的线程不会中断。您需要在发生 TimeoutException 时调用 Future.cancel。并在任务中检查 isInterrupted() 以停止处理。如果您正在调用 api,请确保已选中 isInterrupted()。


答案 2

allowCoreThreadTimeOut超时设置没有帮助,因为它只允许工作线程在一段时间后结束而不工作(请参阅 javadocs)

你说你的工作无限等待外部资源。我敢肯定,这是因为您(或您使用的某些第三方库)默认使用超时无限的套接字。还要记住,当jvm在socket.connect/read上被阻止时,它会忽略Thread.interrupt()。

因此,找出任务中使用的女巫套接字库(以及它的确切使用方式)并更改其默认超时设置。

例如:在Spring内部广泛使用的RestTemplate(在rest客户端,在spring social中,在spring security OAuth中等等)。并且有 ClientHttpRequestFactory 实现来创建 RestTemplate 实例。默认情况下,spring使用SimpleClientHttpRequestFactory,它使用JDK套接字。默认情况下,它的所有超时都是无限的。

因此,找出您冻结的确切位置,阅读其文档并正确配置它。

附言:如果您没有足够的时间并且“感到幸运”,请尝试使用将jvm属性sun.net.client.defaultConnectTimeoutsun.net.client.defaultReadTimeout设置为一些合理的值来运行您的应用程序(有关详细信息,请参阅文档


推荐