簡體   English   中英

如果Spring Scheduled執行在某個固定時間后掛起,則停止

[英]stop Spring Scheduled execution if it hangs after some fixed time

我已經使用Spring Framework的Scheduled計划了我的工作,以使用cron每5分鍾運行一次。 但是有時候我的工作會無限期地等待外部資源,因此我無法在那兒超時。 我無法使用fixedDelay因為以前的進程有時會進入無限等待模式,因此我必須每5分鍾刷新一次數據。

所以我一直在尋找Spring Framework的Scheduled任何選項,以便在fixed-time運行成功或失敗之后停止該進程/線程。

我發現以下設置將我在@Configuration類中放置的keepAliveTime用120秒初始化ThreadPoolExecutor設置。 誰能告訴我這項工作會按我預期的那樣進行。

@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;
}

我不確定這是否會按預期工作。 實際上,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

通過實現Callable,也可以在沒有@Async的情況下執行相同的@Async

編輯:請記住,它將等待直到超時,但是運行任務的線程不會被中斷。 發生TimeoutException時,您將需要調用Future.cancel。 並在任務中檢查isInterrupted()以停止處理。 如果要調用api,請確保已選中isInterrupted()。

allowCoreThreadTimeOuttimeout設置無濟於事,因為它只允許工作線程在一段時間沒有工作后結束(請參閱javadocs)

您說您的工作無限期地等待外部資源。 我敢肯定這是因為您(或您使用的某些第三方庫)使用默認情況下無限超時的套接字。 還請記住,當jvm在socket.connect / read上阻塞時,它會忽略Thread.interrupt()的內容。

因此,找出您的任務中使用的女巫套接字庫(及其使用方式),並更改其默認超時設置。

例如:在Spring內部廣泛使用RestTemplate (在Rest客戶端,Spring社交中,Spring Security OAuth等中)。 並且有ClientHttpRequestFactory實現來創建RestTemplate實例。 默認情況下,spring使用使用JDK套接字的SimpleClientHttpRequestFactory 默認情況下,所有超時都是無限的。

因此,找出凍結的確切位置,閱讀文檔並正確配置。

PS:如果您沒有足夠的時間並且感到“幸運”,請嘗試通過將jvm屬性sun.net.client.defaultConnectTimeoutsun.net.client.defaultReadTimeout設置為一些合理的值來運行您的應用程序(有關更多詳細信息,請參閱文檔

keepAliveTime僅用於清除一段時間以來不需要的工作線程-它對提交給執行程序的任務的執行時間沒有任何影響。

如果花費時間考慮中斷,您可以啟動一個新線程並以超時將其加入,如果未及時完成,則將其中斷。

public class SomeService {

    @Scheduled(fixedRate = 5 * 60 * 1000)
    public void doSomething() throws InterruptedException {
        Thread taskThread = new TaskThread();
        taskThread.start();
        taskThread.join(120 * 000);
        if(taskThread.isAlive()) {
            // We timed out
            taskThread.interrupt();
        }
    }

    private class TaskThread extends Thread {

        public void run() {
            // Do the actual work here
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM