How to gracefully close stream during host shutdown? i am always getting " The operation was canceled." exception on CTRL+C (Asp.NET core 3.1 gRPC template).
`
try
{
await foreach (var response in requestStream.ReadAllAsync(context.CancellationToken))
{
_ = Task.Run(() =>
{
ProcessResponse(response);
});
}
}
catch (Exception) when (context.CancellationToken.IsCancellationRequested)
{
_logger.LogInformation("Server shutdown");
//Graceful shutdown
}
`
Hello @rajeshaz09,
I am a gRPC user, not an author of gRPC but let me try to handle the question.
Answering your question is not related to the specific use case, but based on code I am assuming you have:
I believe that you are not required to call any method on stream, to have it closed or disposed as it is already aware of being cancelled. Moreover, the stream was responsible for throwing an OperationCanceledException you have catched. Let me know if it solves your concerns.
I think that the log information ("Server shutdown") is a bit misleading as you are not doing server application shutdown, but rather reacting to RPC termination.
Hello @rajeshaz09,
I am a gRPC user, not an author of gRPC but let me try to handle the question.Answering your question is not related to the specific use case, but based on code I am assuming you have:
- client streaming scenario,
- an application that is closed using CTRL+C is a client application,
I believe that you are not required to call any method on stream, to have it closed or disposed as it is already aware of being cancelled. Moreover, the stream was responsible for throwing an
OperationCanceledExceptionyou have catched. Let me know if it solves your concerns.I think that the log information ("Server shutdown") is a bit misleading as you are not doing server application shutdown, but rather reacting to RPC termination.
Thanks @wicharypawel
Yes its client streaming scenario. When I press Ctrl+C on server gRPC server console, its taking more time to stop server since cancellationToken is not triggered from client. I modified code as follows to close stream immediately (Using IHostApplicationLifeTime / IHostLifetime)
`
var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(
context.CancellationToken, _lifetime.ApplicationStopping, _lifetime.ApplicationStopped);
try
{
await foreach (var response in _requestStream.ReadAllAsync(cancellationSource.Token))
{
_ = Task.Run(() =>
{
ProcessResponse(response);
});
}
}
catch (Exception) when (cancellationToken.IsCancellationRequested)
{
//Graceful closing of streaming in following cases
//1) host stopping
//2) client ended stream
}
`
I have assumed that you were closing the client's application, but this doesn't change my answer.
gRPC for dotnet is using status codes described here status-codes-docs, cancellation is propagated as a CANCELLED status code that can be generated by both client and server. Any non-OK status is considered an error and handled via exceptions. What I am trying to say is that status will be propagated and it is not required to call any method to close the stream.
Moreover, if there would be such requirement I guess it would be highlighted by the official tutorial or a Dispose method would be available. Please, let us know if that solves your issue.
Yes its client streaming scenario. When I press Ctrl+C on server gRPC server console, its taking more time to stop server since cancellationToken is not triggered from client. I modified code as follows to close stream immediately (Using IHostApplicationLifeTime / IHostLifetime)
When you Ctrl+C Kestrel will attempt to gracefully shutdown. That means it will wait some time for requests that are in-progress to end. That is why you see a delay.
var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(
context.CancellationToken, _lifetime.ApplicationStopping, _lifetime.ApplicationStopped);
This is good. The server will end reading from the stream when ApplicationStopping is triggered. The call then ends on the server and Kestrel stops quickly.
I don't think you need ApplicationStopped:
var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(
context.CancellationToken, _lifetime.ApplicationStopping);
Closing as answered.
Most helpful comment
When you Ctrl+C Kestrel will attempt to gracefully shutdown. That means it will wait some time for requests that are in-progress to end. That is why you see a delay.
This is good. The server will end reading from the stream when
ApplicationStoppingis triggered. The call then ends on the server and Kestrel stops quickly.I don't think you need
ApplicationStopped: