Continuation or callback possible just after throwing an RpcException in gRPC c#?

33 views
Skip to first unread message

Peter Beech

unread,
Mar 18, 2021, 10:00:24 AM3/18/21
to grpc.io

Hi,

I am handling gRPC server-side handler exceptions in an interceptor:

public override async Task<TResponse>    UnaryServerHandler<TRequest, TResponse>( TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation) 
  try 
  { 
    return await continuation(request, context); 
  }
  catch (Exception ex) 
  { 
    LogAndRethrowException(ex); 
    return null; // keep compiler happy 
  }
}

The relevant part of LogAndRethrowException looks like this:

s_log.Debug("Unhandled Exception processing gRPC request", ex); 
throw new RpcException(new Status( StatusCode.Unknown, "Intercepted Unhandled: " + ex.Message));

This is working fine. I'm getting the exceptions on the client and can do the necessary handling I need to do there, plus I'm logging it on the server.

I now need to modify this to crash the server app, as this is the policy where I work. However I still need to get the exception on the client side.

Is there any way in the existing gRPC library to hook into (or get some kind of callback for) the point immediately after the RpcException has been handled by the gRPC and the response sent down the wire to the client?

(The source code mentions that the cancellationToken should be fired whenever anything other than StatusCode.OK is returned, but I tried registering to this and it didn't seem to be the case, at least when throwing an RpcException)

I do have access to a synchronisation context used by the server end, and can send a Post to this to have it throw the exception. However this is probably not reliable since at this point in the interceptor I'm not actually on this sync context so the server might end up crashed too soon. (On the other hand, ideally I'd like it to crash immediately after getting the exception response back to the client, and the sync context may have other stuff queued up...)

I've been looking for hooks in the ServerCallContext, or trying to think of ways of using the continuation creatively, but I can't see any good solution.

I did have a look at the code which actually handles the exception and sends the status, to see if there were any hints there.

In ServerCallHandler.cs, I had a look at the HandleCall method.

The finishedTask (which is set to set to asyncCall.ServerSideCallAsync() at the start) looked promising. I haven't looked into it properly, but as it's awaited at the end, could this provide a way somehow?

(And, a bit of a long shot... but it looks like, with java gRPC, that you can 'send' the exception back to the client by calling responseObserver.onError - is there anything similar in C# gRPC which I could somehow use as an alternative to just throwing the RpcException to get the appropriate response back?)

cheers,

Pete Beech

Reply all
Reply to author
Forward
0 new messages