0

I have two services communicating via gRPC (A calls B) with a cancellation token of X seconds.
The B service might take longer to process the request than the allowed time. In such cases, I'd like to return a partial result if any and receive it back in service A.

Question: How can I get the returned result back in service A, if possible? If not, not what are the alternatives?

From the documentation, deadline is independently tracked on both sides therefore it cannot work. I am assuming the same is for the CancellationToken.

A C#/pseudocode example. Service A calls B with a time limit of 3 seconds, B will require 10 s to complete and will always be cancelled. I'd like to receive value 100, returned if cancelled in the example case back in service A.

Service A:

public async Task<int> GetNumberFromB() 
{
    try 
    {
        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
        var result = await _clientB.GetNumber(new GetNumberRequest(), cancellationToken: cts.Token);
        return result.Value;
    }
    catch (RpcException e) 
    {
        // Get result (100) here
    }
    
    return 0;
}

Service B:

public async Task<GetNumberReply> GetNumber(GetNumberRequest request, ServerCallContext context) 
{
    int value = 0;
    try 
    {
        // It will always be longer than the 3 seconds as request
        await Task.Delay(TimeSpan.FromSeconds(10), context.CancellationToken);  
        value = 1;
    }
    catch (OperationCancelledException ex) 
    {
        // Reached after three seconds, when service A calls the 
        value = 100;
    }
    
    return new GetNumberReply { Value = value };
}
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Jaka Konda
  • 1,385
  • 3
  • 13
  • 35
  • Is your intent to return a result even when the operation is cancelled? If yes, I recommend you reconsider, that'll make your implementation confusing. If you want a partial result if a given threshold is exceeded you should make it explicit i.e. pass in the threshold as a param and have a response object that can communicate whether a partial or full result was received. – HasaniH Dec 02 '21 at 13:43
  • As @HasaniH notes, how is your caller going to know whether they're receiving a partial result, or a full result? You need to set and pass some other sentinel value to indicate this. – Ian Kemp Dec 02 '21 at 13:52
  • @HasaniH B in my case is an aggregator service. It does several calls to other services and returns the aggregated result. So the intermediate result is everything from 3 services, but still waiting for one while the task is cancelled. In this case, it is clearly stated in the response that the service is offline. Now everything is. From the code perspective, I would still except RpcException and status cancelled, but in the exception itself a partial Result. I don't want manual checks in B, is it close to expiration, cancel before the caller does as there are gonna be problems. – Jaka Konda Dec 02 '21 at 14:04
  • @JakaKonda how are you getting the result if you're expecting an Exception? Is the partial result injected in the Exception? – HasaniH Dec 02 '21 at 14:16
  • @HasaniH, In this case, that would be my expectation, yes. I cannot do a streaming call as it's a breaking change. It would resolve my issues by simply forwarding the data. Therefore am looking for options with the current solution. EDIT: There is also a question how to long wait to receive the data if the task is cancelled and then cancelling receiving cancelled result... But as I mentioned, trying to find a nice solution for the current problem. – Jaka Konda Dec 02 '21 at 14:22

0 Answers0