我有一个向服务器开放的双工流式通话,我想在完成之前从客户端取消它。为此,我在IClientStreamWriter上调用CompleteAsync(),并且等待此任务后,我在传递给AsyncEnumerator.MoveNext的取消令牌上调用Cancel。类似于下面的伪代码。我经常发现的结果是在MoveNext中导致RpcException,状态为Cancelled。但是,如果我在CompleteAsync和clientCancelled.Cancel()之间插入一个等待Task.Delay(200)等待,则MoveNext将正常完成。因此,服务器似乎有时间处理CompleteAsync消息并正常结束呼叫。

我的问题是这里推荐的做法是什么?仅调用CompleteAsync而不用使用取消令牌是否安全?如果是这样,那我什么时候使用取消令牌?我可以想象一个场景,就是CompleteAsync引发错误或服务器不以某种方式不与客户端进行通信,即不再有消息。没有取消令牌,我们可能最终会浪费资源。

var clientCancelled = new CancellationTokenSource();

    while (await responseStream.MoveNext(clientCancelled.Token))
    {
        var message = responseStream.Current;
        DoSomething(message);
    }


客户取消请求时调用

await requestStream.CompleteAsync().ConfigureAwait(false);
clientCancelled.Cancel()

最佳答案

这似乎有关:
https://github.com/grpc/grpc/issues/16441

最后一条评论似乎可以回答您的问题:


  取消ResponseStream.MoveNext()等同于取消整个呼叫,并且将导致获得非正常呼叫的StatusCode。
  
  在正常情况下,您应该让您的调用正常完成(即,在客户端上调用CompleteAsync()将其关闭一半,然后从服务器端的处理程序中返回)。这样就不会抛出异常。仅当您实际上要取消呼叫时才使用Cancel()。


简而言之,您不应在此处使用Cancel()。

关于c# - Grpc CompleteAsync,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51083652/

10-10 04:53