SSE subscription makes HotChocolate not being shutdown gracefully
Is there an existing issue for this?
- [X] I have searched the existing issues
Product
Hot Chocolate
Describe the bug
If a SSE subscription alives, HotChocolate does not shutdown gracefully.
Sending Ctrl+C (SIGINT), Kestrel requests connections closed, but HotChocolate keeps connections open and RequestAborted is false.
Steps to reproduce
-
git clone https://github.com/sunghwan2789/hotchocolate.git --branch repro/sse-hangs --single-branch -
dotnet run --project Server - Wait subscription started, and send
Ctrl+C(SIGINT)
Relevant log output
No response
Additional Context?
No response
Version
14.0.0-p.9
Thank you for reporting this.
Can you create a repro?
Updated reproduction, thanks
Also being hit by this. This means we can't reliably update our API, because shutdown hangs whenever there's an active connection. Hoping this will get fixed soon!
Now, I think this is not a bug, but a user-level mistake: the resolver is responsible for completing the subscription on application stopping.
Kestrel also does not abort the client connection immediately:
using System.Runtime.CompilerServices;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpContextAccessor();
var app = builder.Build();
app.MapGet("/", Bar);
_ = DoSubscription(app.Lifetime.ApplicationStopped);
app.Run();
async Task DoSubscription(CancellationToken stopped) {
var client = new HttpClient();
while (!stopped.IsCancellationRequested) {
try {
await foreach (var response in client.GetFromJsonAsAsyncEnumerable<int>("http://localhost:5241/", stopped)) {
Console.WriteLine(response);
}
} catch (Exception ex) {
Console.WriteLine("retry... " + ex);
await Task.Delay(1000, stopped);
}
}
}
async IAsyncEnumerable<int> Bar(IHttpContextAccessor contextAccessor, [EnumeratorCancellation] CancellationToken cancellationToken) {
var context = contextAccessor.HttpContext;
Console.WriteLine(context?.TraceIdentifier);
var i = 0;
while (!cancellationToken.IsCancellationRequested) {
yield return i++;
await Task.Delay(1000, cancellationToken);
}
}
the resolver is responsible for completing the subscription on application stopping
How can this be done? I can't find any information about that in the HC subscription docs.
Updated the reproduction and found that HC does not send a complete event and keep the connection open when an exception is thrown.
Now, I am sure it is a bug.
fixed in v14