2016-10-07 23 views
12

我已經使用Spring Framework的Scheduled來安排我的作業使用cron每5分鐘運行一次。但有時我的工作無限期地等待外部資源,我不能在那裏超時。我無法使用fixedDelay,因爲以前的過程有時會以無限模式進行,我必須每5分鐘刷新一次數據。stop Spring如果它在一段固定的時間後掛起,那麼它會執行計劃執行

所以我在尋找Spring框架的Scheduled中的任何選項,以便在fixed-time成功運行或不成功之後停止該進程/線程。

我找到了下面的設置,其中初始化ThreadPoolExecutor 120秒爲keepAliveTime,我把它放在@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; 
} 
+0

你的代碼不會像你期望的那樣工作。 描述你的隨機懸掛作業的更多細節。 –

回答

7

我不確定這是否會奏效。 Indead keepAlive是用於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

它也可以通過實施贖回

+0

這不會幫助。 主題啓動器在其任務代碼內部存在一些問題,導致永遠阻塞工作線程。我在我的回答中寫到了它。 不解決它 - 池中的所有線程(不管它是Scheduled還是Async Pool)遲早都會耗盡(並且不要忘記每個被阻塞的線程都會消耗堆棧的內存)。 –

+0

您可能是對的,但我們沒有任何信息。 OP詢問他如何超時執行這項任務。 – JEY

1
做不@Async相同

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 
     } 
    } 
} 
+0

這不會幫助。我在我的回答中寫到了它。線程在連接/讀取套接字時被阻塞,忽略中斷。只有socket.close可以提供幫助。但是,所有這些都發生在第三方代碼的內部,所以TS無法關閉套接字,因爲你並不擁有它。 –

+0

你的所有批評都是基於你對導致掛斷的猜測。 – Raniz

5

allowCoreThreadTimeOut超時設置不起作用的原因,它只是允許工作線程沒有工作一段時間後結束(請參閱Javadocs)

你說你的工作將無限等待外部資源。我確定這是因爲你(或者你使用的某個第三方庫)使用套接字,超時默認情況下會超時。 還要記住,當它在socket.connect/read上被阻塞時,jvm會忽略Thread.interrupt()。

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

舉例:有RestTemplate在Spring中廣泛使用(在休息客戶端,在spring社區,在spring安全OAuth等)。並且有ClientHttpRequestFactory實現來創建RestTemplate實例。默認情況下,彈簧使用使用JDK套接字的SimpleClientHttpRequestFactory。默認情況下,所有超時都是無限的。

因此,找出你正在凍結的地方,閱讀它的文檔並正確配置它。

P.S.如果你沒有足夠的時間和「feeling lucky」的嘗試與sun.net.client.defaultReadTimeout設置JVM性能sun.net.client.defaultConnectTimeout一些合理的值來運行你的應用程序(見docs爲更多詳細信息)

+0

如果您使用的是Java郵件,則可以設置以下2個配置。 mail.pop3.connectiontimeout mail.pop3.timeout – vidulahasaranga

0

在Spring Scheduler中,我們可以使用ShedLock在調度程序上執行鎖定和釋放。
另請參閱link