[英]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()。
allowCoreThreadTimeOut和timeout設置無濟於事,因為它只允許工作線程在一段時間沒有工作后結束(請參閱javadocs)
您說您的工作無限期地等待外部資源。 我敢肯定這是因為您(或您使用的某些第三方庫)使用默認情況下無限超時的套接字。 還請記住,當jvm在socket.connect / read上阻塞時,它會忽略Thread.interrupt()的內容。
因此,找出您的任務中使用的女巫套接字庫(及其使用方式),並更改其默認超時設置。
例如:在Spring內部廣泛使用RestTemplate (在Rest客戶端,Spring社交中,Spring Security OAuth等中)。 並且有ClientHttpRequestFactory實現來創建RestTemplate實例。 默認情況下,spring使用使用JDK套接字的SimpleClientHttpRequestFactory 。 默認情況下,所有超時都是無限的。
因此,找出凍結的確切位置,閱讀文檔並正確配置。
PS:如果您沒有足夠的時間並且感到“幸運”,請嘗試通過將jvm屬性sun.net.client.defaultConnectTimeout和sun.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.