Closed evgenyvsmirnov closed 8 months ago
There is built-in support for writing a file:
@RequestMapping(path = "/file/{id}", method = GET, produces = APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
public Resource downloadFile(ServerWebExchange exchange, @PathVariable("id") String id) {
return new FileSystemResource(getFile());
}
On servers that support zero-copy like Reactor Netty, this will perform a zero-copy file transfer (see ResourceHttpMessageWriter
), or otherwise will fall back on DataBufferUtils.read(resource, ...)
which internally uses DataBufferUtils.readAsynchronousFileChannel
(see ResourceEncoder
).
In short I don't know the underlying cause for the above, but I would suggest using the built-in support if possible, which relies on more efficient zero-copy transfer, or otherwise Resource
writing via DataBufferUtils
.
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
Please consider the following REST controller method which employs DataBufferUtils to transmit a file:
Expected behaviour: a 200, 4xx or 5xx is transmitted to the client or the connection is closed amid the transmission. Actual behaviour: client hangs
So once in a while I stumble across the following stacktraces in the production logs (the bad thing is that I can't reproduce them with a test – it seems reactor-netty disregards the clients TCP window size which the test could capitalize on):
My first concern is "Queue is full: Reactive Streams source doesn't respect backpressure" – have no idea how could I "respect backpressure" – your expertise would be valued.
The second and the foremost one is "Error [java.lang.UnsupportedOperationException] for HTTP GET "/file/file5412465168127", but ServerHttpResponse already committed (200 OK)'". Evidence suggests that reactor-netty can't keep up with the transmission, fails, the error is propagated to the application exception handler which composes a 5xx response, but HttpWebHandlerAdapter afterwards detects that at least the status line is in the wire and rightly rejects 5xx response (the only thing it can do in such a situation). I came up with the idea of the conditional exception suppression:
hoping to prevent my exception handler from the error processing. In my eyes its an odd solution because such situations are inherent in HTTP servers.
Are there any flaws in my implementation or the problem is caused by an issue in DataBufferUtils or elsewhere?
Environment: