Skip to content

Error with StatusCode Internal thrown when a server is unavailable for a client running on .NET Framework 4.8 instead of Unavailable #2581

Open
@SayakMukhopadhyay

Description

@SayakMukhopadhyay

What version of gRPC and what language are you using?

Grpc.Net.Client 2.67.0 and C#

What operating system (Linux, Windows,...) and version?

Windows 11

What runtime / compiler are you using (e.g. .NET Core SDK version dotnet --info)

.NET Framework 4.8

What did you do?

I have a GRPC server written in Java Spring Boot. I want to ensure proper retries if the server is unavailable. From what I understand, the client will retry if a retryable status code is returned. I would have thought that if the server is unavailable, I should get a status code of StatusCode.Unavailable but instead I get StatusCode.Internal. Setting StatusCode.Internal as a retryable status code works so far as the retries are concerned but that error is thrown for a variety of reasons that I don't want to retry on. Following is how I am setting up the channel

WinHttpHandler winHttpHandler = new WinHttpHandler();
winHttpHandler.ServerCertificateValidationCallback = TlsValidationCallback;

GrpcChannel channel = GrpcChannel.ForAddress("https://localhost:9090", new GrpcChannelOptions
{
    HttpHandler = winHttpHandler,
    ServiceConfig = new ServiceConfig
    {
        MethodConfigs =
        {
            new MethodConfig
            {
                Names = { MethodName.Default }, RetryPolicy =
                    new RetryPolicy
                    {
                        InitialBackoff = TimeSpan.FromSeconds(2),
                        MaxBackoff = TimeSpan.FromSeconds(30),
                        BackoffMultiplier = 1.5,
                        RetryableStatusCodes = { StatusCode.Internal }
                    }
            }
        }
    },
    MaxRetryAttempts = 5
});

Client = new HelloService.HelloServiceClient(channel);

Client.SendMessahe(new HelloRequest { Name = "hello"});

What did you expect to see?

I expected to get a StatusCode.Unavailable when the server is not running.

What did you see instead?

I am getting a StatusCode.Internal instead.

The full error message is

Unhandled Exception: Grpc.Core.RpcException: Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: An error occurred while sending the request. WinHttpException: Error 12029 calling WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, 'A connection with the server could not be established'.", DebugException="System.Net.Http.HttpRequestException: An error occurred while sending the request.") ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.Http.WinHttpException: Error 12029 calling WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, 'A connection with the server could not be established'.
   at System.Threading.Tasks.RendezvousAwaitable`1.GetResult()
   at System.Net.Http.WinHttpHandler.<StartRequestAsync>d__122.MoveNext()
   --- End of inner exception stack trace ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at Grpc.Net.Client.Internal.GrpcCall`2.<RunCall>d__82.MoveNext() in /_/src/Grpc.Net.Client/Internal/GrpcCall.cs:line 508
   --- End of inner exception stack trace ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Grpc.Net.Client.Internal.Retry.RetryCallBase`2.<GetResponseCoreAsync>d__80.MoveNext() in /_/src/Grpc.Net.Client/Internal/Retry/RetryCallBase.cs:line 119
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Grpc.Net.Client.Internal.HttpClientCallInvoker.BlockingUnaryCall[TRequest,TResponse](Method`2 method, String host, CallOptions options, TRequest request) in /_/src/Grpc.Net.Client/Internal/HttpClientCallInvoker.cs:line 153
   at Grpc.Core.Interceptors.InterceptingCallInvoker.<BlockingUnaryCall>b__3_0[TRequest,TResponse](TRequest req, ClientInterceptorContext`2 ctx) in /_/src/Grpc.Core.Api/Interceptors/InterceptingCallInvoker.cs:line 53
   at Grpc.Core.ClientBase.ClientBaseConfiguration.ClientBaseConfigurationInterceptor.BlockingUnaryCall[TRequest,TResponse](TRequest request, ClientInterceptorContext`2 context, BlockingUnaryCallContinuation`2 continuation) in /_/src/Grpc.Core.Api/ClientBase.cs:line 205
   at Grpc.Core.Interceptors.InterceptingCallInvoker.BlockingUnaryCall[TRequest,TResponse](Method`2 method, String host, CallOptions options, TRequest request) in /_/src/Grpc.Core.Api/Interceptors/InterceptingCallInvoker.cs:line 50
   at MyRunner.RunnerService.RunnerServiceClient.ReplyRunner(HelloRequest request, CallOptions options) in my-folder\my-runner\MyRunner\obj\Debug\Protos\RunnerGrpc.cs:line 110
   at MyRunner.RunnerService.RunnerServiceClient.ReplyRunner(HelloRequest request, Metadata headers, Nullable`1 deadline, CancellationToken cancellationToken) in my-folder\my-runner\MyRunner\obj\Debug\Protos\RunnerGrpc.cs:line 105
   at MyRunner.RunnerCallbacks.ReplyRunner(RunnerReplyModel RunnerReplyModel) in my-folder\my-runner\MyRunner\RunnerCallbacks.cs:line 17
   at Beezlabs.RPAHive.Lib.RPARunnerTemplate.RunRunner(RunnerExecutionModel RunnerExecutionModel)
   at MyRunner.Program.<Main>d__0.MoveNext() in my-folder\my-runner\MyRunner\Program.cs:line 42
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at MyRunner.Program.<Main>(String[] args)

Anything else we should know about your project / environment?

TlsValidationCallback is a function that I am using to validate a custom certificate which is why managing my own WinHttpHandler is neded.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions