タスクが完了したかどうかを確認するためにリモート サーバーをポーリングする必要があるシナリオがあります。タスクが完了したら、別の呼び出しを行って結果を取得します。
当初は、ポーリングにはSingleThreadScheduledExecutor
with を使用する必要があると考えていました。scheduleWithFixedDelay
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture future = executor.scheduleWithFixedDelay(() -> poll(jobId), 0, 10, TimeUnit.SECONDS);
public void poll(String jobId) {
boolean jobDone = remoteServer.isJobDone(jobId);
if (jobDone) {
retrieveJobResult(jobId);
}
}
Runnable
しかし、何も返さないを提供することしかできないため、 がいつ完了するのか、あるいは完了するかどうかがscheduleWithFixedDelay
わかりません。 呼び出しとは一体何を意味するのでしょうか? どのような結果を待っているのでしょうか?future
future.get()
リモート タスクが完了したことを初めて検出したときに、別のリモート呼び出しを実行し、その結果を の値として設定したいと思います。これには、 を自分のメソッドに転送し、そのメソッドがそれを自分のメソッドに転送して、最終的にタスクを完了させるという方法をfuture
使用できることCompletableFuture
を検討しました。poll
retrieveTask
CompletableFuture<Object> result = new CompletableFuture<Object>();
ScheduledFuture future = executor.scheduleWithFixedDelay(() -> poll(jobId, result), 0, 10, TimeUnit.SECONDS);
public void poll(String jobId, CompletableFuture<Object> result) {
boolean jobDone = remoteServer.isJobDone(jobId);
if (jobDone) {
retrieveJobResult(jobId, result);
}
}
public void retrieveJobResult(String jobId, CompletableFuture<Object> result) {
Object remoteResult = remoteServer.getJobResult(jobId);
result.complete(remoteResult);
}
しかし、これには多くの問題があります。まず、CompletableFuture
この種の使用を意図していないようです。代わりに、がキャンセル/完了したときにCompletableFuture.supplyAsync(() -> poll(jobId))
を適切にシャットダウンして、返された をexecutor
キャンセルするにはどうすればいいと思いますか? ポーリングは、まったく異なる方法で実装する必要があるように感じます。future
CompletableFuture
ベストアンサー1
CompletableFutures はこれを行うための優れた方法だと思います。
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private void run() {
final Object jobResult = pollForCompletion("jobId1")
.thenApply(jobId -> remoteServer.getJobResult(jobId))
.get();
}
private CompletableFuture<String> pollForCompletion(final String jobId) {
CompletableFuture<String> completionFuture = new CompletableFuture<>();
final ScheduledFuture<Void> checkFuture = executor.scheduleAtFixedRate(() -> {
if (remoteServer.isJobDone(jobId)) {
completionFuture.complete(jobId);
}
}, 0, 10, TimeUnit.SECONDS);
completionFuture.whenComplete((result, thrown) -> {
checkFuture.cancel(true);
});
return completionFuture;
}