简体   繁体   English

为什么我的执行器服务线程挂在 java 中?

[英]Why is my executor service thread hanging in java?

I have a class which contains a scheduled executor service, to run a task every 5 seconds.我有一个 class 包含一个预定的执行程序服务,每 5 秒运行一次任务。 Sometimes, the task itself may take longer than 5 seconds due to retry logic that I have implemented.有时,由于我已实现的重试逻辑,任务本身可能需要超过 5 秒的时间。 In this case, I ASSUME that even though I have the scheduler to run the task every 5 seconds, it simply waits until the retry is complete.在这种情况下,我假设即使我有调度程序每 5 秒运行一次任务,它也只是等到重试完成。 But, after 2 failed attempts, I see my failure log and I no longer see a call being made every 5 seconds.但是,在 2 次失败尝试后,我看到了失败日志,并且不再看到每 5 秒拨打一次电话。

import io.dropwizard.lifecycle.Managed;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import net.jodah.failsafe.Failsafe;
import net.jodah.failsafe.RetryPolicy;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.IDBI;

@Slf4j
public class DBTask implements Managed
{
    private final IDBI dbi;
    private final String validationQuery;
    private final ScheduledExecutorService runner;
    private final RetryPolicy policy;

    public DBHealthCheckTask(@NonNull final IDBI dbi, @NonNull final String validationQuery)
    {
        this.dbi = dbi;
        this.validationQuery = validationQuery;
        runner = Executors.newSingleThreadScheduledExecutor();
        policy = new RetryPolicy()
            .withDelay(5 , TimeUnit.SECONDS)
            .withMaxRetries(2)
            .retryOn(Exception.class);
    }

    @Override
    public void start() throws Exception
    {
        int intervalSecs = 5;
        runner.scheduleAtFixedRate(this::runWithRetry, intervalSecs, intervalSecs, TimeUnit.SECONDS);
    }

    @Override
    public void stop()
    {
        runner.shutdown();
    }

    private void runWithRetry()
    {
        Failsafe.with(policy)
            .onRetry(r -> log.info("Database connection failed.", r))
            .onFailure(r -> log.warn("WARNING- Database is unhealthy.", r))
            .run(this::run);
    }

    private void run()
    {
        try (Handle handle = dbi.open())
        {
            handle.execute(validationQuery);
        }
    }
}

Once I see the "WARNING" log, I expect that the task continues again, and then it will retry another 2 times with a delay of 5 seconds before I see another "WARNING" log.一旦我看到“WARNING”日志,我希望该任务会再次继续,然后它会在我看到另一个“WARNING”日志之前延迟 5 秒再重试 2 次。 But I only see one log, after that nothing ever happens.但我只看到一个日志,之后什么都没有发生。

Method runWithRetry will throw exception when 2 times retry failed.方法runWithRetry会在 2 次重试失败时抛出异常。 For schedule, if exception caught when executing task, would not set next task execute.对于调度,如果在执行任务时发现异常,则不会设置下一个任务执行。 So if we want task always scheduled, need catch exception for task manually.因此,如果我们希望任务始终被调度,则需要手动捕获任务异常。 In your case, do something like:在您的情况下,请执行以下操作:

private void runWithRetry()
{
    try{
        Failsafe.with(policy)
        .onRetry(r -> log.info("Database connection failed.", r))
        .onFailure(r -> log.warn("WARNING- Database is unhealthy.", r))
        .run(this::run);
    }catch(Exception e){
        //handle exception, make sure no exception rethrow
    }
}

WARNING- Database is unhealthy , only printed after the last round of retry, so to add some log in run() , you'll see the retry process. WARNING- Database is unhealthy ,仅在最后一轮重试后打印,因此在run()中添加一些日志,您将看到重试过程。

private void run() {
    // add some log here
    // System.out.println("hello");
    try (Handle handle = dbi.open()) {
        handle.execute(validationQuery);
    }
}

The explaination from JavaDoc JavaDoc的解释

If multiple policies, are configured, this handler is called when execution is complete and any policy fails.如果配置了多个策略,则在执行完成且任何策略失败时调用此处理程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM