最佳实践:"Soft Cancellation" 使用 gRPC

Best Practice: "Soft Cancellation" with gRPC

在我看来,gRPC 的内置取消支持在以下意义上非常激进:如果我在客户端调用取消,通信通道将立即关闭。服务器得到通知并可以进行清理工作,但是清理完成后似乎没有机会通知客户端。

如果我想要以下“软取消”行为,我应该怎么做?

  1. 客户请求取消
  2. 服务器收到取消请求并开始清理
  3. 服务器完成清理并关闭通信通道
  4. 客户收到取消程序已完成的通知

可以使用请求流和 oneof 关键字来实现此行为:

service ServiceName{
    rpc Communicate (stream Request) returns (Response);
}

message Request {
    oneof request_oneof {
        ActualRequest actual = 1;
        CancellationRequest cancellation = 2;
    }
}

这实现起来应该不难,但看起来也很麻烦。您认为预期的方式是什么?

对于一元 RPC,除了取消之外别无选择。您需要将其设为 client-streaming RPC 以便对其他通信事件进行编码。

对于 client-streaming 和 bidi-streaming RPC,一个常见的模式是客户端延迟 half-close。当客户端完成时,客户端 half-closes 通知服务器客户端已完成。服务器然后执行清理并可以使用状态消息干净地关闭流。您可以采用相同的方法,利用 half-close:

service ServiceName {
    rpc Communicate (stream ActualRequest) returns (Response);
}

message ActualRequest {...}

Streaming 允许您创建这样的自定义协议,但只有您的应用程序知道如何与该协议交互。例如,代理无法启动此协议的“优雅取消”。所以你应该只在你真正需要它的时候使用它,你仍然应该正确地实现“硬”取消,即使你可能不经常使用它。