ScheduledExecutorService зависание при выполнении задачи - PullRequest
0 голосов
/ 28 октября 2019

У меня есть экземпляр ScheduledExecutorService - размер пула потоков по некоторым бизнес-требованиям равен 1 - который через некоторое время начинает зависать. Задания все еще отправляются, пул потоков все еще «работает», однако задача никогда не выполняется.

Чтобы предотвратить вечный запуск потока, я включил тайм-аут, который выполняет задачу исключительно после заданного времени ожидания. ,Локально все работает нормально (включая тайм-ауты), но при развертывании на сервере через некоторое время он начинает зависать.

Я думаю, это вызвано некоторой блокировкой во время выполнения задачи, но я ожидал тайм-аутчтобы решить эту проблему (я что-то упустил?).

Метод, отвечающий за выполнение задач:

private synchronized <T> CompletableFuture<T> submit(Supplier<T> supplier, ScheduledExecutorService delegate) {
    CompletableFuture<T> completableFuture = new CompletableFuture<>();
    completableFuture.whenComplete((input, exception) -> {
        if (completableFuture.isCompletedExceptionally()) {
            log.error("Error executing", exception);
        }
    });

    delegate.schedule(() -> {
        Timeouter timeouter = new Timeouter(30, completableFuture);
        completableFuture.complete(new Task<>(supplier).run(completableFuture, timeouter));
    }, 10, TimeUnit.SECONDS);

    return completableFuture;
}

И вспомогательные классы, отвечающие за тайм-аут:

public class Timeouter extends TimerTask {

    private Timer timer = new Timer();
    private int timeout;
    private CompletableFuture<?> completableFuture;

    Timeouter(int timeout, CompletableFuture<?> completableFuture) {
        this.timeout = timeout;
        this.completableFuture = completableFuture;
    }

    public void start() {
        timer.schedule(this, Duration.ofSeconds(timeout).toMillis());
    }

    void stop() {
        timer.cancel();
        timer.purge();
    }

    @Override
    public void run() {
        completableFuture.completeExceptionally(
                new TimeoutException(String.format("Job timed-out after %s seconds", timeout)));
    }

}

public class Task<T> {

    private Supplier<T> supplier;

    public Task(Supplier<T> supplier) {
        this.supplier = supplier;
    }

    public T run(CompletableFuture<T> completableFuture, Timeouter timeouter) {
        timeouter.start();
        try {
            T response = supplier.get();
            return response;
        } catch (Throwable t) {
            completableFuture.completeExceptionally(t);
            return null;
        } finally {
            timeouter.stop();
        }
    }
}

Любая помощь будет оценена.

...