有没有办法在客户端上通过返回响应来确定服务器提前完成客户端流调用?

问题描述 投票:0回答:1

我有以下案例。客户端使用客户端流(通过 grpc-dotnet)将文件上传到服务器。在某些情况下,服务器可能决定忽略客户端流并立即返回响应。由于客户端不知道服务器的决定,因此它继续调用 RequestStream.WriteAsync() 并最终得到

Grpc.Core.RpcException: 'Status(StatusCode="OK", Detail="")'

问题是:是否有一种优雅的方式可以提前知道调用已经完成,而不会进行错误的写入尝试?

浏览 grpc-dotnet 源代码,我设法通过反射

AsyncClientStreamingCall.RequestStream.Call.ResponseFinished
标志找到了解决方案,但它看起来比使用已知 StatusCode 处理异常更糟糕。

客户端伪代码:

private static async Task CallUploadStream(GrpcService.GrpcServiceClient client)
{
    using var streamingCall = client.UploadStream();

    // First call
    await WriteAsync();

    // Delay
    await Task.Delay(TimeSpan.FromSeconds(1));

    // Second call
    await WriteAsync(); // Grpc.Core.RpcException: 'Status(StatusCode="OK", Detail="")'

    await streamingCall.RequestStream.CompleteAsync();
    await streamingCall;

    return;

    Task WriteAsync()
    {
        return streamingCall.RequestStream.WriteAsync(
            new UploadStreamRequest
            {
                Bytes = ByteString.CopyFrom(new byte[1]),
            }
        );
    }
}

Protobuf 合约:

syntax = "proto3";
package grpc.debug.contract.v1;
option csharp_namespace = "GrpcDebug.Contract";
import "google/protobuf/empty.proto";

service GrpcService {
  rpc UploadStream(stream UploadStreamRequest) returns (google.protobuf.Empty);
}

message UploadStreamRequest { bytes bytes = 1; }

立即返回响应的服务器:

public class GrpcServiceV1 : GrpcService.GrpcServiceBase
{
    public override Task<Empty> UploadStream(IAsyncStreamReader<UploadStreamRequest> requestStream,
        ServerCallContext context)
    {
        return Task.FromResult(new Empty());
    }
}
c# .net grpc grpc-dotnet
1个回答
0
投票

所以要明确一点:对

WriteAsync
的调用是否会因
RpcException
而出错?您可以在每次写入之前尝试检查
call.ResponseAsync.IsCompleted
(或者可能是为了获取下一个块而进行的每一项工作),但这本质上是一种竞争条件,您必须始终准备好捕获异常即使您检查之前的行。如果您在这里模拟的是基本上一个
Stream
,或者至少:您正在以多个块发送大量有效负载,那么您可能也对 protobuf-net.Grpc 工作感兴趣,以添加二进制流原生支持;在 NuGet 的版本中,目前仅限于服务器 returning a
Stream
,但这主要是因为这是我有一个消费者迫切需要的场景 - 计划是添加所有方向组合,并支持除
Stream
,如
Pipe

© www.soinside.com 2019 - 2024. All rights reserved.