【问题标题】:Using gRPC, how should I handle partial results between my server and client?使用 gRPC,我应该如何处理服务器和客户端之间的部分结果?
【发布时间】:2023-03-19 14:36:01
【问题描述】:

这更像是一个 API 设计问题,但我很好奇其他人对这种情况的看法:

假设我有一台服务器,客户端将向我发送他们想要检索数据的项目列表,我返回 item:data 的映射。

当然首先我会检查我的缓存,查询我的数据库。让我们假设数据库查询花费的时间太长(无论出于何种原因),所以我有足够的时间终止以将部分结果(在缓存中找到)返回给客户端。

我想让客户知道两件重要的事情:

  1. 这是您的部分结果(如果您选择使用它们)。
  2. 这就是我无法解决您的其余问题的原因 (err.ConnDeadlineExceeded)

现在我计划只返回部分结果和一个 nil 错误。原因是我的大多数客户首先检查err != nil,只有当这是真的时,他们才会真正费心查看结果。

但这感觉不对,因为我正在删除有关数据库超时的信息。有什么建议的解决方案吗?

【问题讨论】:

    标签: api go grpc rpc partial


    【解决方案1】:

    正如您所确定的,这完全取决于您希望客户端如何响应 API 响应:

    results, err := app.Api(ctx, queryMessage)
    

    部分结果指示器将驻留在results 或非零err

    ldapsearch 为例 - 如果您提供大小限制 - API 将返回最多该数量的结果,但返回非零返回码 (sizeLimitExceeded)。客户需要知道检查该特定代码以及是否要处理发送的部分结果。

    nil 错误似乎更成功,因此您需要在results 消息中包含大小限制。 One suggestion是定义一个proto枚举:

    enum extraStatusCode {
        UNKNOWN         = 0;  // not set/used
        SIZELIMIT       = 1;
        TIMELIMIT       = 2;
    }
    

    并将其包含在您的结果原型消息中:

    message Result {
        repeated Record records = 1;  // results (full or partial)
    
        // ...
    
        extraStatusCode = 15; // indicate if partial results 
    }
    

    【讨论】:

      【解决方案2】:

      我建议返回非零错误,然后通过特定调用 errors.Is(err, yourPackage.ConnDeadlineExceeded) 提取错误检查。例如,这种检查使用 GORM (https://gorm.io/docs/error_handling.html#ErrRecordNotFound) 来验证错误是来自数据库的“非犯罪”零结果响应还是需要调用代码执行更多操作的严重错误。

      【讨论】:

      • gRPC 仅提供有限(和数字)的错误代码集 - 因此无法通过错误值返回丰富的错误:github.com/grpc/grpc/blob/master/doc/statuscodes.md
      • 此外,这个解决方案还有很多工作要做,因为我必须改变每个下游服务当前检查错误的方式。
      猜你喜欢
      • 1970-01-01
      • 2013-08-10
      • 2022-11-16
      • 1970-01-01
      • 2019-11-20
      • 1970-01-01
      • 2013-10-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多