-
Notifications
You must be signed in to change notification settings - Fork 523
Graceful Shutdown Empty Response #1501
Comments
Investigating. |
Your code causes a deadlock higher up in the stack. Cancelling the token calls On the thread were your first request is being serviced, Here are the call stacks: Thread 1
Thread 2
I'm not sure what you're trying to do is a supported scenario. Paging @pakrym @davidfowl @NTaylorMullen @rynowak |
This was an over simplification of a problem that I was trying to resolve but was able to reproduce with this example. I wanted to make sure it wasn't something deeper in our code base so I created an empty dotnet webapi project to run my tests in. Our scenario is that we spin up new micro services to replace old ones as new versions become available (continuous delivery). We use Consul for service discovery and when the new ones come online they replace the old serviceID of the previous micro service. We want the old version of the microservice to drain and finish all its requests and exit. The problem we kept running in to is when we requested kestrel to gracefully shutdown, all the active connections would fail and stall out rather than complete as intended. NOTE: I tried requesting Kestrel to shutdown via an external thread rather than on a request and get the same result. This leads me to believe that the deadlock exists in all scenario's if you try to gracefully shutdown Kestrel. Is there another way that I missed to ask Kestrel to drain all its connections properly and exit? |
To be perfectly clear. I want to be able to signal Kestrel to exit and have it handle any active connections it has left before returning back to the command prompt. Even if those active connections take upwards of 60-120 seconds as a worst case scenario. |
@CesarBS I've been looking through this all weekend and read your diagnoses probably 10 times. While it makes sense what you are saying, I still fail to see how to resolve this. You've mentioned this is possibly an unsupported scenario, but the scenario is nothing more than wanting to stop Kestrel and fulfilling the remaining requests without taking new ones. What I'm not understanding is why are things being disposed and locked when you request Kestrel to be stopped. Shouldn't Kestrel simply stop the listening socket and enter a drain mode until all connections are completed (or shutdown timeout lapses) before anything is even disposed? At a higher level I imagine something like this (pseudo code).
|
Since this is critical for me, I gave up on trying to determine how to handle this properly inside Kestrel and implemented my own version of drain. I'm putting this here in case anyone else needs a work around for the time being. In program.cs, create and use a cancellation token source.
Pass the token to Run
While this code doesn't belong here, I'm putting it here for illustration purposes. In Startup.cs, create some static variables to track state.
Add a method for Stop.
And finally in Configure, add a custom I believe these work as a chain (hence next), so this should be first before all other
And finally, you can call |
It works even without adding
Also, in case of using some sort of load balancer, like docker swarm, it could be handy to redirect to the same url, so request will be processed by other running nodes:
|
Created middleware based on a proposed workaround. |
I think this will solve the problem: Lets track the issue over there |
@cphillips83 Kestrel supports graceful shutdown, but by default it gives active connections a short period of time to complete their work (5 seconds). You can increase the shutdown timeout by setting |
I cannot find |
I downloaded and was reading the WebHostBuilderTests in Hosting to try and understand if there was a similar mechanism that avtc created with his GracefulShutdown extension. I need to save state once the Kestrel web server is shutdown and has no active connections. It seems that the Hosting is a generic IServer lifecycle management, and not doing active connection counting. Is there a similar hook or singleton in the DI that I can reference to determine if Kestrel is quiescent? Thank you. |
I have attached a demo gist of the problem. I have tried shutting down Kestrel in several ways and they all produce the same result.
Test:
First run this command which will start a request that delays until the 2nd request is sent
curl http://localhost:5000/api/values/1
This request attempts to shutdown Kestrel
curl -X DELETE http://localhost:5000/api/values/1
Problem:
return "value";
executescurl: (52) Empty reply from server
after Kestrel ShutdownTimeout elapsesReferences:
#1026 - Graceful shutdown and draining
#247 - Hangs for 2-3 seconds when a request is made even after its served
test code
The text was updated successfully, but these errors were encountered: