tommwq.work/aip

AIP-217 不可达资源

· [tommwq@126.com]
编号 217
原文链接 https://google.aip.dev/217
状态 批准
创建日期 2019-08-26
更新日期 2019-08-26

有时,用户可能会请求一系列资源,而其中某些资源暂时不可用。最典型的场景是跨集合读。例如用户可能请求返回多个上级位置的资源,但其中某个位置暂时不可达。此时仍然需要向用户提供所有可用资源,同时告诉客户有部分缺失。

指南

如果查询数据的方法由于若干资源暂时不可达而部分失败,应答消息 必须 包含一个域来表明这一点:

message ListBooksResponse {
  // 符合请求的书籍。
  repeated Book books = 1;

  // 下一页的令牌(如果还有符合请求的书籍)
  string next_page_token = 2;

  // 不可达资源。
  repeated string unreachable = 3 [
    (google.api.field_behavior) = UNORDERED_LIST
  ];
}
  • 必须 是一个重复字符串域, 应该 命名为 unreachable
  • 必须 包含不可达的、或者阻碍访问所请求集合的资源名字,例如所请求集合的上级资源不可达。
    • 例如整个位置不可达,阻止了访问所请求的本地资源集合,则包含位置资源。
  • 必须 包含 服务相对 资源名, 不得 包含完整资源名、资源URI或简单资源标识。有关定义请参考AIP-122
    • 例如 Book 资源不可达,则 服务相对 资源名 "shelves/scifi1/books/starwars4" 包含在 unreachable 中,而非 完整 资源名 "//library.googleapis.com/shelves/scifi1/books/starwars4" 、/上级相对/ 资源名 "books/starwars4" 、资源标识 "starwars4" 或资源URI。
  • 应答 不得 提供导致所需资源不可达的问题的任何其他信息。
    • 例如应答不能包含额外的域,包括每个 unreachable 条目的错误原因。
  • 服务 必须 提供方法,让用户能够发出具体请求,接收额外错误信息。例如使用标准的Get或List方法,请求不可达集合的上级资源。
    • 服务 必须 允许用户使用更严格的参数重发请求。
  • 出现在 unreachable 中的资源名字 可能 是异构的。
    • unreachable应该 在文档中记录可能包含的资源,注明资源列表可能在将来扩展。
    • 例如整个位置和不同位置的特定资源都不可达,那么不可达位置的名字(如 "projects/example123/locations/us-east1" )和不可达资源的名字(如 "projects/example123/locations/europe-west2/instances/example456" )都将出现在 unreachable 中。
  • unreachable不得 在列表内提供语义上有意义的顺序或结构。换句话说,unreachable 必须 是一个无序列表。
    • 因此 unreachable必须 使用 UNORDERED_LIST 域行为注释(参考AIP-203)。

重要 如果按照规范要求,由于位置或资源不可达,无法返回数据(例如请求列出某个出版商的资源,但该出版商不可达),服务必须终止整个请求,返回错误信息。

分页

在准备分页远程过程调用(例如AIP-132标准List方法)结果时,如果服务遇到不可达资源或集合, 必须 遵照下列执行:

  • unreachable 应答域中包含不可达资源的资源名。
    • 资源名字 必须 是不可达资源或集合的最适当的范围。
      • 例如某地区的特定区域不可达,不可达资源名是区域位置(如 projects/example/locations/us-west1-a )。如果整个地区不可达,资源名是区域位置(如 projects/example/locations/us-west1 )。
    • 如果发现资源不可达,无论分页参数(如 order_by )如何限制, 必须 包含资源名。
  • 如果先前不可达资源恢复可用,分页参数也允许包含这些资源,在后续页中添加它们。
    • 根据分页参数确定包含哪些资源。如果用户没有设定排序规则,遵守文档要求的默认排序规则。
    • 例如在有序分页调用中,地区 projects/example/locations/us-west1 在第一页中不可用。如果包含该地区资源将违反排序规则,那么这些资源不包含在后续页中。
    • 类似的,如果重发同一请求,先前不可达资源恢复可用, 必须 在分页参数约束下添加它们。
  • 如果适当上调资源范围后,不可达资源名数量仍然超过文档要求的最大值,限制应答中返回的不可达资源名数量。
    • 最大值 必须 直接记录在 unreachable 域注释中。
    • 最大值与调用者设定的 page_size 无关。

保持原有行为

如果修改分页行为会产生AIP-180描述的不兼容变更,服务 可以 继续保持以前实现的 unreachable 分页行为,但 必须unreachable 域文档中直接记录具体行为。

适配部分成功

现存API中,默认行为不同于上述指南的(例如API调用返回错误状态而非部分结果),适配 unreachable 模式时 必须 执行下列操作:

  • 必须 保持默认行为,避免行为变更不兼容。
    • 例如默认行为是当任何位置不可达时返回错误,*必须* 保持原默认行为 。
  • 请求消息 必须 包含 bool return_partial_success 域。
  • 应答消息 必须 包含标准 repeated string unreachable 域。
  • 上述两域 必须 同时添加。

如果请求中的 bool return_partial_success 域设定为 true ,API 必须 按照上述指南,填写 repeated string unreachable 应答域。

message ListBooksRequest {
  // Standard List request fields...

  // Setting this field to `true` will opt the request into returning the
  // resources that are reachable, and into including the names of those that
  // were unreachable in the [ListBooksResponse.unreachable] field. This can
  // only be `true` when reading across collections e.g. when `parent` is set to
  //  `"projects/example/locations/-"`.
  bool return_partial_success = 4;
}

message ListBooksResponse {
  // Standard List Response fields...

  // Unreachable resources. Populated when the request opts into
  // `return_partial_success` and reading across collections e.g. when
  // attempting to list all resources across all supported locations.
  repeated string unreachable = 3 [
    (google.api.field_behavior) = UNORDERED_LIST
  ];
}

部分成功的粒度

如果请求的 bool return_partial_success 域设定为 true ,而请求范围超出了API能够合理判断不可达资源能力的粒度,API 应该 返回 INVALID_ARGUMENT 错误,附带说明问题的细节。例如某个API仅在跨集合读时支持 return_partial_success ,如果请求范围限定为特定上级资源集合,则返回 INVALID_ARGUMENT 错误。API支持的粒度 必须return_partial_success 域文档中记录。

理由

使用服务相对资源名

根据AIP-122定义的相对资源名通常是在服务内部或跨服务引用资源的最佳选择,尤其在外部服务明确时。完整资源名严格来说不太好用(例如需要在客户端进行解析),并且对于 unreachable 来说过于具体。资源URI并非与传输无关,因此它们在gRPC标准方法中不可用,而简单资源标识无法提供充足信息,准确指出在异构资源列表中哪个资源不可达。

在应答中提供最少额外错误详情

不可达资源的上下文可能存在敏感信息,系统状态在调用之间也是变化的。因此最好使用更具体的远程过程调用,依赖服务获取特定资源或上级资源的更多详情。这可以让服务在处理上级资源时进行全面检查、判定系统状态。而不是将可能涉密或过期的信息,胡乱塞入遭遇资源不可达的调用中。

不对 unreachable 进行排序

要在许多API之间达成统一, unreachable 内容不存在特定的、有序的语义结构非常重要。如果每个API在标准域中生成特定顺序,无论是客户端或服务器如何实现,都无法保证正确。

每个页都包含 unreachable 资源

每个页都包含 unreachable 资源,允许终端用户立即识别页面是否完整,不需要遍历所有结果。用户未必会分页到末尾,重要的是尽快在页中提示缺少不可达资源。此外,这允许用户识别潜在问题,在后续调用中处理。最后,保留不可达资源信息直到分页末尾,这需要服务在完全隔离的API调用中保持一组相互独立的状态。

使用请求域作为选项

引入新的请求域作为适配部分成功行为的选项,是即能传达用户意图,又能保持默认行为向后兼容的最好的办法。另一种选择,改变默认行为,加入 unreachable 应答域,将导致不向后兼容的变更。预期当某个资源不可达时遇到失败的用户,可能会认为应答成功表示已经包含全部资源。

同时引入域

同时引入请求和应答域,是为了防止只添加一个域时,可能出现无效的中间状态。如果只添加 unreachable ,用户可能假定域为空意味着已经返回全部资源,而实际未必如此。如果只添加 return_partial_success ,用户将无法得知哪些资源不可达。

部分成功的粒度限制

在请求范围的某个粒度级别上,API可能完全无法枚举不可达资源。例如全局性API可能无法提供本地集合级别的粒度。在此场景中,如果 return_partial_success=true 时主动返回错误,可以避免用户遭遇风险:系统存在问题,但用户未收到不可达列表,误以为已经检索全部资源。这与本指南一致:对于无法完整执行的请求,主动返回失败。

历史

分页指南

最初关于填充 unreachable 域的指南的核心思路是:将这些内容视为分页结果。这意味着分页资源与不可达资源不会出现在同一应答(即页)中。用户需要遍历所有结果,才能发现是否存在不可达资源。有关更改的原因,请参考理由部分。

进一步阅读

  • 关于跨集合读,请参考AIP-159

修订记录

  • 2024-07-29 修改指南格式,添加具体的资源名格式
  • 2024-07-26 修改分页指南要求。
  • 2024-07-19 添加适配部分成功的指南。