У меня есть следующий код (в результате my previous question), который планирует задачу на удаленном сервере, а затем опроса для завершения с использованием ScheduledExecutorService#scheduleAtFixedRate
. По завершении задачи он загружает результат. Я хочу вернуть вызывающему абоненту Future
, чтобы они могли решить, когда и как долго блокировать, и дать им возможность отменить задачу.CompletedFuture # whenComplete не вызывается, если thenApply используется
Моя проблема заключается в том, что если клиент отменяет Future
, возвращенный методом download
, блок whenComplete
не выполняет. Если я удалю thenApply
, то делает. Очевидно, я что-то не понимаю о композиции Future
... Что я должен изменить?
public Future<Object> download(Something something) {
String jobId = schedule(something);
CompletableFuture<String> job = pollForCompletion(jobId);
return job.thenApply(this::downloadResult);
}
private CompletableFuture<String> pollForCompletion(String jobId) {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
CompletableFuture<String> completionFuture = new CompletableFuture<>();
ScheduledFuture<?> checkFuture = executor.scheduleAtFixedRate(() -> {
if (pollRemoteServer(jobId).equals("COMPLETE")) {
completionFuture.complete(jobId);
}
}, 0, 10, TimeUnit.SECONDS);
completionFuture
.whenComplete((result, thrown) -> {
System.out.println("XXXXXXXXXXX"); //Never happens unless thenApply is removed
checkFuture.cancel(true);
executor.shutdown();
});
return completionFuture;
}
На той же ноте, если я:
return completionFuture.whenComplete(...)
вместо
completionFuture.whenComplete(...);
return completionFuture;
whenComplete
также никогда не выполняется. Это кажется мне очень противоречивым. Не следует ли логически возвращать Future
whenComplete
, к которому я должен придерживаться?
EDIT:
Я изменил код явно резервного размножать отмены. Это отвратительное и нечитаемым, но это работает, и я не мог найти лучший способ:
public Future<Object> download(Something something) throws ChartDataGenException, Exception {
String jobId = schedule(report);
CompletableFuture<String> job = pollForCompletion(jobId);
CompletableFuture<Object> resulting = job.thenApply(this::download);
resulting.whenComplete((result, thrown) -> {
if (resulting.isCancelled()) { //the check is not necessary, but communicates the intent better
job.cancel(true);
}
});
return resulting;
}
Он даже не входит в блок 'whenComplete'. Я помещаю точку останова и 'System.out.print' внутри, и ни одна точка останова не попадает, и линия не печатается. Это произойдет, если я удалю бит 'thenApply'. – kaqqao
По моему мнению, это должно быть обратное тому, что вы сообщаете. 'completeFuture.whenComplete()' является чистой функцией и не должен ничего менять в том, как работает 'completeFuture'. Если вы не вернете результат 'whenComplete', он должен стать недоступным и подчиняться GC. –
Абсолютно согласен. Но это то, что я вижу ... Если вернуть результат 'whenComplete' и' cancel' его немедленно, я не получаю XXXXX в консоли. С другой стороны, если я верну оригинал 'completeFuture' и' cancel' _that_, я это сделаю. – kaqqao