Akka HTTP version: 3.0.0-RC1
How to reproduce:
sudo ifconfig lo0 mtu 1500complete and ToResponseMarshallableConnection: close.Expected result:
Client should receive normally
Actual result:
Client got Recv failure: Connection reset by peer
This causes problems with some proxy like nginx or kong because they send Connection: close to upstream by default.
Thanks for reporting. I'll mark as bug though I'm not sure about it.
It could be like this: when the server sees Connection: close on a request it fully closes the connection directly after having sent out the last bit of the response which might close the socket too soon?
@keimoon which client did you use? Could you try to capture a network trace using tcpdump and attach it here? Thanks ;)
Also I can only reproduce the bug with HttpEntity.Strict
Great, thanks @keimoon. That will help a lot.
I had a quick try, this issue can be reproduced using your instructions.
The problem is that when the HTTP server decides to close the connection, it does so by completely killing the HTTP stack which will complete the write-side of the TCP connection stream and cancel the read-side. If cancel arrives first (which seems to be the case), the Tcp stream implementation will abort the connection (= socket.close with soLinger(0)). The result is that the OS just doesn't know about the connection any more and if any data was not sent yet this data is lost and any further packets will be responded with RST.
We've seen issues like that for a long time (IIRC also with spray). I guess the solution could be just to keep cancellation from reaching the TCP connection. (I don't think that this creates leaks, hopefully leaks would be prevented by the idle-timeout on the connection but it might make sense to think a bit about it.)
Great. Currently we are implementing an work around that will use HttpEntity.Chunked if the response body is large.
We migrated our app to akka-http 10.0.0, and received the same error - when using anything, that sends header "Connection: close" (nginx, curl), the request will fail on Strict entities, that are larger than 128K.
Error in curl:
curl: (56) Recv failure: Connection reset by peer
Chunked does not help - changed response entity to HttpEntity.Chunked(mediaType, Source(Seq(ByteString(prettyJsonString)))), and now it works with curl, but still fails with nginx. Is there any reliable workaround?
Same here :( Would really appreciate a way to solve this.
So if I understand correctly, we'd need a "CancellationBarrier" that can be "opened" by external signal, which we could use to resolve the race (making it always "cancel" after the completion went "all the way"). Reasonable @jrudolph ?
We might not need to send cancellation to the tcp stream at all but I haven't checked if that would work.
I reproduced it with this code https://github.com/jrudolph/akka-http/commit/a929a03f9d68177f9f04153dac6409acddbcc9dd and curl:
curl -vvv -H "connection:close" http://localhost:9001/big > /dev/null
Workaround with nginx here: https://github.com/akka/akka/issues/19542
Tested a locally published version of Akka HTTP and I no longer see connection resets.
Cool, thanks for testing!
I am perhaps seeing this again with nginx.
I'm serving an html page with Akka-Http 10.0.9 with getFromFile().
The file contains an tag with
src containing base64 encoded image.
Nginx has this in the error logs.
upstream prematurely closed connection while reading upstream
The error is resolved by using the workaround in akka/akka#19542
@antonkatz Is the traffic served over HTTPS?
@antonkatz we fixed issue #1219 in 10.0.10 which was similar to this bug when running on HTTPS. Can you check if 10.0.10 still has the issue?
Most helpful comment
Workaround with
nginxhere: https://github.com/akka/akka/issues/19542