I belive there is no answear in the whole internet for this as it is probably very complex but I will go ahead and ask.
Basically, I want to have a cross communication between multiple Spring applications. Each of them is serving resources in a static way, here is the link for that topic. This serving is capitalized by other application instances that can download those files on request (for now I am transferring files via HTTP). I was able to download files thanks to the Downlolad and save file from ClientRequest using ExchangeFunction in Project Reactor SO question.
Right now I want to elevate my code so that in case of the connection issue or application being temporarily unavailable for the given timeout I am able to resume the downloading of the file. I configured the WebClient timeouts as in this article.
Right now, I thought that such code would actually let me handle temporarily unavailable services:
final AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(targetPath, StandardOpenOption.WRITE);
Flux<DataBuffer> fileData = Mono.just(filePath)
.map(file -> targetPath.toFile().exists() ? targetPath.toFile().length() : 0)
.map(bytes -> webClient
.get()
.uri(uri)
.accept(MediaType.APPLICATION_OCTET_STREAM)
.header("Range", String.format("bytes=%d-", bytes))
.retrieve()
.onStatus(HttpStatus::is4xxClientError, clientResponse -> Mono.error(new CustomException("4xx error")))
.onStatus(HttpStatus::is5xxServerError, clientResponse -> Mono.error(new CustomException("5xx error")))
.bodyToFlux(DataBuffer.class)
)
.flatMapMany(Function.identity());
DataBufferUtils
.write(fileData , fileChannel)
.map(DataBufferUtils::release)
.doOnError(throwable -> {
try {
fileChannel.force(true);
} catch (IOException e) {
e.printStackTrace();
}
})
.retry(3)
.doOnComplete(() -> {
try {
fileChannel.force(true);
} catch (IOException e) {
e.printStackTrace();
}
})
.doOnError(e -> !(e instanceof ChannelException), e -> {
try {
Files.deleteIfExists(targetPath);
} catch (IOException exc) {
exc.printStackTrace();
}
})
.doOnError(ChannelException.class, e -> {
try {
Files.deleteIfExists(targetPath);
} catch (IOException exc) {
exc.printStackTrace();
}
})
.doOnTerminate(() -> {
try {
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
})
.blockLast();
But apparently I am getting a full stack of errors whenever I kill my second instance of application starting with:
reactor.netty.http.client.PrematureCloseException: Connection prematurely closed DURING response
2019-10-25T15:41:53.602+0200 [ERROR] [xxx] [N/A:N/A] [r.core.publisher.Operators] { thread=reactor-http-nio-4 } Operator called default onErrorDropped
reactor.core.Exceptions$BubblingException: reactor.netty.http.client.PrematureCloseException: Connection prematurely closed DURING response
at reactor.core.Exceptions.bubble(Exceptions.java:154)
at reactor.core.publisher.Operators.onErrorDropped(Operators.java:512)
at reactor.netty.channel.FluxReceive.onInboundError(FluxReceive.java:343)
at reactor.netty.channel.ChannelOperations.onInboundError(ChannelOperations.java:399)
at reactor.netty.http.client.HttpClientOperations.onInboundClose(HttpClientOperations.java:258)
at reactor.netty.channel.ChannelOperationsHandler.channelInactive(ChannelOperationsHandler.java:121)
and also later in the same stack trace:
2019-10-25T15:41:53.602+0200 [WARN] [xxx] [N/A:N/A] [i.n.c.AbstractChannelHandlerContext] { thread=reactor-http-nio-4 } An exception 'reactor.core.Exceptions$BubblingException: reactor.netty.http.client.PrematureCloseException: Connection prematurely closed DURING response' [enable DEBUG level for full stacktrace] was thrown by a user handler's exceptionCaught() method while handling the following exception:
reactor.core.Exceptions$BubblingException: reactor.netty.http.client.PrematureCloseException: Connection prematurely closed DURING response
at reactor.core.Exceptions.bubble(Exceptions.java:154)
at reactor.core.publisher.Operators.onErrorDropped(Operators.java:512)
at reactor.netty.channel.FluxReceive.onInboundError(FluxReceive.java:343)
at reactor.netty.channel.ChannelOperations.onInboundError(ChannelOperations.java:399)
at reactor.netty.http.client.HttpClientOperations.onInboundClose(HttpClientOperations.java:258)
at reactor.netty.channel.ChannelOperationsHandler.channelInactive(ChannelOperationsHandler.java:121)
The exceptions itself are not much of a problem but the point being is that my download does not resume after I boot my application back up to live.
So yeah, my question is, how could I possibly resume the downloading and how should/could I handle such exceptions as in here?