Невозможно распространить пользовательское исключение из исключений в CompletableFuture - PullRequest
0 голосов
/ 17 января 2020
           public void executeAsync(Task task){
             CompletableFuture.runAsync(
                () -> {
                    task.execute(CompletableFuture.completedFuture(null), executor)
                            .exceptionally(
                                    ex -> {
                                        log.error(ex.getMessage(), ex);
                                        log.debug(
                                                "exception from executor" + ex.getStackTrace());
                                        throw new RunTimeException(
                                                ex);
                                    })
                            .join();
                },
                executor);
     }


    public static Task execute(Task... tasks) {
    return (future, executor) ->
            tasks.length == 0
                    ? future
                    : CompletableFuture.allOf(
                            Arrays.stream(tasks)
                                    .map(t -> t.execute(future, executor))
                                    .toArray(CompletableFuture[]::new));
}

Здесь в приведенном выше коде я вижу журнал исключений из метода executeAsyn c () для одной из задач, однако при вызове функции для этого метода не удается отловить исключение, выданное из него.

Любые указатели будут полезны в этом отношении, кажется, ничего не работает для меня. Мне нужно отловить любое исключение, выброшенное из любой задачи, и соответственно обновить БД.

1 Ответ

1 голос
/ 20 января 2020

Насколько я знаю, единственная асинхронная библиотека, которая способна обрабатывать ошибки в слоях, - это DF4J (разработанный мной). Уровень определяется как Dataflow объект:

 Dataflow upper = new Dataflow();  
 Dataflow nested = new Dataflow(upper);

Dataflow - это график, состоящий из асинхронных процедур и вложенных Dataflow с. Когда исключение генерируется из асинхронной c процедуры, оно распространяется на родительские потоки данных. Мы можем отслеживать только поток данных верхнего уровня на предмет всех ошибок.

Класс, наиболее близкий к CompletableFuture, равен AsyncFunc. AsyncFunc s может иметь асинхронные параметры для получения значений от других AsyncFunc s или CompletableFuture s, но в этом примере мы их не используем.

Для каждого вида AsyncFun c рекомендуется объявить свой собственный класс:

class StringToInt extends AsyncFunc<Integer> {
    String argumnet;

    // in constructor, link this async function to the parent dataflow
    public StringToInt(Dataflow df, String argumnet) {
        super(df);
        this.argumnet = argumnet;
    }

    @Override
    protected Integer callAction() throws Throwable {
        return Integer.valueOf(argumnet); // can throw NumberFormatException
    }
}

Этот класс можно использовать следующим образом:

    // start good asyncFunc tied to upper dataflow
    new StringToInt(upper, "10").start();
    // start bad asyncFunc tied to nested dataflow
    new StringToInt(nested, "not an integer").start();
    try {
        // here wait all started async functions to finish
        upper.blockingAwait(100);
        Assert.fail("exception expected");
    } catch (CompletionException e) {
       // here we catch first error from all async functions
        Throwable cause = e.getCause();
        cause.printStackTrace();
        Assert.assertEquals(NumberFormatException.class, cause.getClass());
    }

It рекомендуется использовать последнюю версию DF4J, клонированную из Github.

...