I have a dotnet framework application which performs POST api requests to a remote server running Apache. It intermittently fails with the error:
The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.
This occurs on the second request to the server when done over a keepalive TLS connection, and so occurs more frequently in production systems under heavy load and less frequently or not at all in development environments.
We have tried:
Expect: 100-Continue
header behaviour (ServicePoint.Expect100Continue = false
)ServicePoint.SetTcpKeepAlive()
)Disabling HTTP keep-alive appears to work around the issue. (HttpWebRequest.KeepAlive = false
)
Is there a way to solve this without disabling http keep-alive?
The Apache setting KeepAliveTimeout
defaults to 5s of inactivity before an idle keep-alive connection will be closed. (https://httpd.apache.org/docs/2.4/mod/core.html#keepalivetimeout)
This leads to a condition where:
KeepAliveTimeout
), apache sends a FIN packet to close the underlying connection.The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.
This is particularly a problem in large POST calls (say, calling a SOAP API) where forming the payload may take a nontrivial amount of time.
Possible solutions are:
HttpWebRequest.GetRequestStream()
until immediately before starting to send data.HttpWebRequest.KeepAlive = false
). However that note if any other thread in your application is using keep-alive then the problem will occur (the two requests above can be in entirely different threads)Note importantly that this behaviour (of "locking a stream to a socket") only seems to occur in dotnet framework, not in dotnet 5/core.