使用 gRPC,我应该如何处理服务器和客户端之间的部分结果?

Using gRPC, how should I handle partial results between my server and client?

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

假设我有一个服务器,客户会向我发送他们想要检索数据的项目列表,然后我 return 一张 item:data.

的地图

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

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

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

目前我打算只 return 部分结果和零错误。这样做的原因是我的大多数客户首先检查 err != nil,只有当这是真的时,他们才会真正费心去查看结果。

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

正如您所确定的,这实际上取决于您希望客户如何对 API 响应做出反应:

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

部分结果指标将驻留在 results 或非零 err.

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

A nil 错误似乎更可行,因此您需要在 results 消息中包含已达到大小限制。 是定义一个原型枚举:

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 
}

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