Open jameswoodley opened 11 months ago
We also just got this on the server:
System.IO.IOException: The request stream was aborted.
---> Microsoft.AspNetCore.Connections.ConnectionAbortedException: The HTTP/2 connection faulted.
--- End of inner exception stack trace ---
at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
at System.IO.Pipelines.Pipe.GetReadAsyncResult()
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2MessageBody.ReadAsync(CancellationToken cancellationToken)
at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
at Grpc.AspNetCore.Server.Internal.PipeExtensions.ReadSingleMessageAsync[T](PipeReader input, HttpContextServerCallContext serverCallContext, Func`2 deserializer)
at Grpc.AspNetCore.Server.Internal.CallHandlers.UnaryServerCallHandler`3.HandleCallAsyncCore(HttpContext httpContext, HttpContextServerCallContext serverCallContext)
at Grpc.AspNetCore.Server.Internal.CallHandlers.ServerCallHandlerBase`3.<HandleCallAsync>g__AwaitHandleCall|8_0(HttpContextServerCallContext serverCallContext, Method`2 method, Task handleCall)
And this on the client
Grpc.Core.RpcException: Status(StatusCode="Internal", Detail="Bad gRPC response. HTTP status code: 400")
at Grpc.Net.Client.Internal.Retry.RetryCallBase`2.GetResponseCoreAsync()
at FindYourGrind.Auth.Sdk.Users.Users.GetUserById(Guid userId, CancellationToken cancellationToken)
at B2B.Educator.Engine.Application.UserInfo.Queries.Favorites.GetUserFavoritesHandler.Handle(GetUserFavorites request, CancellationToken cancellationToken) in /home/runner/work/B2B-Educator-Engine/B2B-Educator-Engine/src/Application/UserInfo/Queries/Favorites/GetUserFavorites.cs:line 51
at B2B.Educator.Engine.Application.Common.Behaviours.PerformanceBehaviour`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken) in /home/runner/work/B2B-Educator-Engine/B2B-Educator-Engine/src/Application/Common/Behaviours/PerformanceBehaviour.cs:line 59
at B2B.Educator.Engine.Application.Common.Behaviours.ValidationBehaviour`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken) in /home/runner/work/B2B-Educator-Engine/B2B-Educator-Engine/src/Application/Common/Behaviours/ValidationBehaviour.cs:line 41
at B2B.Educator.Engine.Application.Common.Behaviours.AuthorizationBehaviour`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken) in /home/runner/work/B2B-Educator-Engine/B2B-Educator-Engine/src/Application/Common/Behaviours/AuthorizationBehaviour.cs:line 0
at B2B.Educator.Engine.Application.Common.Behaviours.UnhandledExceptionBehaviour`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken) in /home/runner/work/B2B-Educator-Engine/B2B-Educator-Engine/src/Application/Common/Behaviours/UnhandledExceptionBehaviour.cs:line 47
at B2B.Educator.Engine.Application.Common.Behaviours.RetryPolicyBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken) in /home/runner/work/B2B-Educator-Engine/B2B-Educator-Engine/src/Application/Common/Behaviours/RetryPolicyBehavior.cs:line 100
at B2B.Educator.Engine.Application.Common.Behaviours.TransactionBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken) in /home/runner/work/B2B-Educator-Engine/B2B-Educator-Engine/src/Application/Common/Behaviours/TransactionBehavior.cs:line 52
at B2B.Educator.Engine.Application.Common.Behaviours.OutboxBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken) in /home/runner/work/B2B-Educator-Engine/B2B-Educator-Engine/src/Application/Common/Behaviours/OutboxBehavior.cs:line 0
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
at B2B.Educator.Engine.Api.Controllers.UserInfoController.GetUserFavorites(CancellationToken cToken) in /home/runner/work/B2B-Educator-Engine/B2B-Educator-Engine/src/WebUI/Controllers/UserInfoController.cs:line 97
at lambda_method212(Closure , Object )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
This is a difficult problem to solve. There are many layers between the client and the server in Azure App Service. The first set of client and server errors suggests the HTTP request reaches the server but not all the data is arriving. How big is the message the client is sending to the server?
What version of Grpc.Net.Client, Grpc.AspNetCore and .NET are you using? I recommend using the latest version of Grpc.Net.Client.
One option is to simplify your scenario. You could create a channel without any customization and see whether it works. For example:
_channel = GrpcChannel.ForAddress(environment.Address, new GrpcChannelOptions
{
Credentials = ChannelCredentials.Create(new SslCredentials(), credentials)
});
If the issue disappears after the changes, it could narrow the problem to something in the retry logic.
Another thing to try is disabling the channel's advanced connectivity features. You can do that by setting a property on the handler:
var handler = new SocketsHttpHandler();
handler.Properties["__GrpcLoadBalancingDisabled"] = true;
_channel = GrpcChannel.ForAddress(environment.Address, new GrpcChannelOptions
{
Credentials = ChannelCredentials.Create(new SslCredentials(), credentials),
HttpHandler = handler
});
Hey @JamesNK thanks for the reply! So the message being sent is pretty small. Protos are:
UUID:
message UUID {
string value = 1;
}
GetUserByIdRequest
message GetUserByIdRequest {
FindYourGrind.Grpc.UUID id = 1;
}
Versions Grpc.Net.Client: 2.59.0 Grpc.AspNetCore: 2.59.0 Dotnet: 7
In terms of the retry, the same issue was happening before the retry logic was added, it was actually added to try and resolve/mitigate this issue
I'll try the simplified scenario first, if no joy I'll disable the advanced connectivity features and report back.
With regards hosting in Azure, would you recommend a different hosting solution than Azure App Service?
Unfortunately the simplified scenario hasn't worked. So moving on to disabling the advanced connectivity features
Channel is now created as:
var credentials = CallCredentials.FromInterceptor(async (context, metadata) =>
{
var token = await tokenGenerator.GetApplicationToken(context.CancellationToken).ConfigureAwait(false);
metadata.Add("Authorization", $"Bearer {token}");
});
var handler = new SocketsHttpHandler();
handler.Properties["__GrpcLoadBalancingDisabled"] = true;
_channel = GrpcChannel.ForAddress(environment.Address, new GrpcChannelOptions
{
Credentials = ChannelCredentials.Create(new SslCredentials(), credentials)
});
Will report back from that change
Unfortunately no dice - I think for now we're going to have to go back to Web Api
Damn.
In one way it is good: reducing the gRPC client to its most basic behavior means the problem isn't there. It is bad because the problem is somewhere that is harder to change: HttpClient or ASP.NET Core or Azure App Service. I think the likely cause is Azure App Service and how it handles HTTP/2. It's the complex variable in this solution. Something causes the request to stop, and then the request is killed after 100 seconds.
Two interesting experiments you could make:
I'll pass this issue on to Azure App Service people to see whether they have any ideas.
btw I'm on holiday this week and back Nov 27.
Hi @JamesNK - we've been running Web API over HTTP2 for just over a week now and now seen these same issues. So it's definitely a gRPC thing I think!
Hope you had a good holiday! Thanks for the help
Hi @JamesNK - we've been running Web API over HTTP2 for just over a week now and now seen these same issues. So it's definitely a gRPC thing I think!
I think there is a typo in your message. Do you have this problem with Web API or is it just gRPC?
Hi @JamesNK - we've been running Web API over HTTP2 for just over a week now and now seen these same issues. So it's definitely a gRPC thing I think!
I think there is a typo in your message. Do you have this problem with Web API or is it just gRPC?
You're correct. Should have said noT seen these same issues. Web Api has been working fine
Encountering the same problem, GRPC cannot throw
I'm encountering a similar issue, but what solves it is moving the app service to a new app service plan.
@jameswoodley did you ever come back to implementing gRPC ? I'm thinking our only option is to move back to REST calls
@somatech-uk no we decided to go back to REST Web Api and be done with it. No issues since
We've recently added gRPC to our system, hosted in Azure using a Linux App Service. It seems intermittently we get hit with a client hitting our timeout (1min 40). DataDog has tracing and logging enabled, and we get next to no information:
The exception thrown on the server is:
The client throws:
Client Channel Setup:
Upon disposal of the class, we call
_channel.ShutDownAsync(); _channel.Dispose();
I've recently added in some retry and keep alive logic, but is there anything else we should be doing? I'm tearing my hair out with why intermittently it takes so long