在使用CompletableFuture
的PlayWS执行长时间下载时,有时会达到定义的请求超时。发生这种情况时,PlayWS似乎不会引发异常(至少在我的配置中),因此即使数据已损坏,也无法将下载标记为失败并进行了处理。
请原谅这段可憎的代码:
final CompletionStage<WSResponse> futureResponse = this.playWS.client
.url(importSource.getDownloadUrl())
.setMethod(HttpMethod.GET)
.setRequestTimeout(Duration.ofSeconds(5)) // When the timeout is reached, the download gets canceled
.stream();
try {
futureResponse
.thenAccept(res -> {
try (OutputStream outputStream = Files.newOutputStream(file.toPath())) {
final Source<ByteString, ?> responseBody = res.getBodyAsSource();
final Sink<ByteString, CompletionStage<Done>> outputWriter =
Sink.foreach(bytes -> {
outputStream.write(bytes.toArray());
});
responseBody
.runWith(outputWriter, this.playWS.materializer)
.whenComplete((value, error) -> {
System.out.println("VALUE: "+value); // == "Done"
System.out.println("Error: "+error); // == null
})
.exceptionally(exception -> {
throw new IllegalStateException("Download failed for: " + importSource.getDownloadUrl(), exception);
})
.toCompletableFuture().join();
} catch (final IOException e) {
throw new IllegalStateException("Couldn't open or write to OutputStream.", e);
}
})
.exceptionally(exception -> {
throw new IllegalStateException("Download failed for: " + importSource.getDownloadUrl(), exception);
})
.toCompletableFuture().get();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("Couldn't complete CompletableFuture.", e);
}
我是从根本上做错了还是这是一个错误?
我看到的唯一解决方案是:
计算接收到的字节并将它们与
Content-Length header
进行比较。将请求超时设置为-1(不确定)。
感谢您的任何建议。
最佳答案
我认为有些复杂化了。
您可以将Future
或CompletableStage
附加到Source
。 Akka Streams具有比CompletableFuture
更健壮的API(我认为)
final CompletionStage<WSResponse> futureResponse = this.playWS.client
.url(importSource.getDownloadUrl())
.setMethod(HttpMethod.GET)
.setRequestTimeout(Duration.ofSeconds(5))
.stream();
Source<WSResponse> source = Source.fromCompletableStage(futureResponse);
source.map(...).filter(...).recover(...).runforeach(..., playWS.materializer)