web-dev-qa-db-ja.com

一定時間後にハングした場合、Springのスケジュールされた実行を停止する

私はSpring FrameworkのScheduledを使用して、cronを使用して5分ごとに実行するようにジョブをスケジュールしました。しかし、いつか私の仕事が外部リソースを無限に待ち、そこでタイムアウトを設定することができません。 fixedDelayを使用できません。前のプロセスが無限に待機するモードになり、5分ごとにデータを更新する必要があるためです。

そのため、Spring FrameworkのScheduledで、プロセスが正常に実行されたかどうかにかかわらず、そのプロセス/スレッドをfixed-timeの後に停止するオプションを探していました。

ThreadPoolExecutor@Configurationクラスに入れたkeepAliveTimeに対して120秒で初期化する設定を以下で見つけました。誰もが私が期待したようにこの作品を私に言うことができますか.

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

これが期待どおりに機能するかどうかはわかりません。実際、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なしで同じことを行うこともできます。

編集:タイムアウトまで待機しますが、タスクを実行しているスレッドは中断されないことに注意してください。 TimeoutExceptionが発生した場合は、Future.cancelを呼び出す必要があります。そしてタスクでisInterrupted()をチェックして処理を停止します。 APIを呼び出す場合は、isInterrupted()がチェックされていることを確認してください。

8
JEY

allowCoreThreadTimeOutおよびtimeout設定は、作業スレッドのみを許可するのに役立ちません仕事なしでしばらくして終了する(javadocsを参照)

あなたはあなたの仕事が外部リソースを無限に待つと言います。あなた(またはあなたが使用しているサードパーティのライブラリ)がデフォルトで無限のタイムアウトでソケットを使用しているためだと思います。また、socket.connect/readでブロックされている場合、jvmがThread.interrupt()を無視することにも注意してください。

したがって、タスクで使用されているウィッチソケットライブラリ(およびその正確な使用方法)を調べ、デフォルトのタイムアウト設定を変更してください。

例:RestTemplateがSpring内で広く使用されています(残りのクライアント、Spring Social、Spring SecurityでOAuth RestTemplateインスタンスを作成するための ClientHttpRequestFactory 実装があります。デフォルトでは、スプリングは SimpleClientHttpRequestFactory JDKソケットを使用し、デフォルトではすべてのタイムアウトは無限です。

だから、あなたがどこでフリーズしているのかを見つけ、ドキュメントを読んで適切に設定してください。

追伸十分な時間がなく「幸運を感じる」場合は、jvmプロパティSun.net.client.defaultConnectTimeoutSun.net.client.defaultReadTimeoutを適切な値に変更します(詳細は docs を参照)

7

keepAliveTimeは、しばらくの間必要のなかったワーカースレッドを一掃するためのものです。executorに送信されたタスクの実行時間に影響を与えることはありません。

時間のかかるものが割り込みを尊重している場合は、新しいスレッドを開始してタイムアウトで結合し、時間内に完了しない場合は割り込みをかけることができます。

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
        }
    }
}
2
Raniz