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

Posted

技术标签:

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

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

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

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

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

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

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

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

【问题讨论】:

【参考方案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 此外,这个解决方案还有很多工作要做,因为我必须改变每个下游服务当前检查错误的方式。

以上是关于使用 gRPC,我应该如何处理服务器和客户端之间的部分结果?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理服务器和客户端之间的时区?

grpc-go源码剖析五十九之客户端一侧,是如何处理截止时间呢?

为什么对gRPC做负载均衡会很棘手?

GRPC 如何处理出现多次的指针?

Node.JS、Express 和 Heroku - 如何处理 HTTP 和 HTTPS?

如何处理mio中的错误?