You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
What version of gRPC and what language are you using?
C#
gRPC codegen compiled with Grpc.Tools 2.40.0
Affected process importing Grpc.AspNetCore 2.50.0
What operating system (Linux, Windows,...) and version?
Windows
What runtime / compiler are you using (e.g. .NET Core SDK version dotnet --info)
.net7
What did you do?
My service implements a server streaming call, which as part of its implementation polls an rpc from another service. We also have ContextPropagationInterceptor added to the pipeline.
Simplified example:
publicoverrideasync Task Stream(StreamRequestrequest,IServerStreamWriter<StreamResponse>responseStream,ServerCallContextcontext){usingCancellationTokenSourcects=new CancellationTokenSource();while(!context.CancellationToken.IsCancellationRequested){// _otherService is a codegen'd grpc clientvarresponse=await _otherService.GetStateAsync(new GetStateRequest(),new Metadata(), cancellationToken: cts.Token);await responseStream.WriteAsync(response, context.CancellationToken);}}
What did you expect to see?
All resources cleaned up
What did you see instead?
Process memory increases over time -- memory dump + ETW trace indicates there's a leak of Linked2CancellationTokenSource objects (+ associated CallbackRegistration, CallbackNode).
ContextPropagationInterceptor allocates a LinkedCancellationTokenSource and sets it up to be disposed when the containing GrpcCall is disposed. However, it doesn't seem like the call is ever implicitly disposed.
/// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything.
/// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call.
/// As a result, all resources being used by the call should be released eventually.
/// </summary>
/// <remarks>
/// Normally, there is no need for you to dispose the call unless you want to utilize the
/// "Cancel" semantics of invoking <c>Dispose</c>.
/// </remarks>
It seems like either AsyncUnaryCall should be automatically disposing its AsyncCallState at some point, or ContextPropagationInterceptor has a faulty assumption that AsyncCallState will be disposed in normal control flow.
The text was updated successfully, but these errors were encountered:
What version of gRPC and what language are you using?
C#
gRPC codegen compiled with Grpc.Tools 2.40.0
Affected process importing Grpc.AspNetCore 2.50.0
What operating system (Linux, Windows,...) and version?
Windows
What runtime / compiler are you using (e.g. .NET Core SDK version
dotnet --info
).net7
What did you do?
My service implements a server streaming call, which as part of its implementation polls an rpc from another service. We also have ContextPropagationInterceptor added to the pipeline.
Simplified example:
What did you expect to see?
All resources cleaned up
What did you see instead?
Process memory increases over time -- memory dump + ETW trace indicates there's a leak of Linked2CancellationTokenSource objects (+ associated CallbackRegistration, CallbackNode).
ContextPropagationInterceptor allocates a LinkedCancellationTokenSource and sets it up to be disposed when the containing GrpcCall is disposed. However, it doesn't seem like the call is ever implicitly disposed.
Using unary calls as an example:
grpc-dotnet/src/Grpc.AspNetCore.Server.ClientFactory/ContextPropagationInterceptor.cs
Line 153 in c9c902c
grpc-dotnet/src/Grpc.AspNetCore.Server.ClientFactory/ContextPropagationInterceptor.cs
Lines 115 to 121 in c9c902c
grpc-dotnet/src/Grpc.AspNetCore.Server.ClientFactory/ContextPropagationInterceptor.cs
Line 236 in c9c902c
grpc-dotnet/src/Grpc.AspNetCore.Server.ClientFactory/ContextPropagationInterceptor.cs
Lines 211 to 215 in c9c902c
I can work around this by adjusting my code, but it doesn't feel expected/ergonomic from a user's perspective:
Particularly considering the comment on AsyncUnaryCall:Dispose:
grpc-dotnet/src/Grpc.Core.Api/AsyncUnaryCall.cs
Lines 138 to 147 in c9c902c
It seems like either AsyncUnaryCall should be automatically disposing its AsyncCallState at some point, or ContextPropagationInterceptor has a faulty assumption that AsyncCallState will be disposed in normal control flow.
The text was updated successfully, but these errors were encountered: