AIP-216 状态
编号 | 216 |
---|---|
原文链接 | https://google.aip.dev/216 |
状态 | 批准 |
创建日期 | 2018-10-01 |
更新日期 | 2018-10-01 |
许多API资源都带有“状态”概念:通常指资源在其生命周期中的位置。例如,虚拟机可能处于配置中、可用、关闭中,或者其他几种可能的情况之一。作业或查询可能处于准备运行、运行中、已完成等。
指南
需要表达状态的资源 应当 使用枚举,枚举 应当 称为 State
(或者如果要更具体,以 State
结尾)。如果枚举只用作消息内的域, 应当 将枚举嵌套在其所描述的消息中。
重要 我们使用词汇
State
而非Status
(后者用于HTTP和gRPC状态)。
枚举值
理想情况下,Google API在表达相同的语义概念时,使用同一个词汇。通常会有多个词汇可以表达同一个状态,而我们的客户经常同时使用多个API,如果我们使用统一的词汇,对他们来说更容易。
在高层次上:
- 可用的资源是
ACTIVE
的(优先于“ready”或“available”等词汇)。 - 已完成(通常时终止)请求操作的资源,状态使用过去分词(通常以
-ED
结尾),例如SUCCEEDED
(不是“successful”)、FAILED
(不是“failure”)、DELETED
、SUSPENDED
等。 - 当前正在进行状态变更的资源,状态使用现在分词(通常以
-ING
结尾),例如RUNNING
、CREATING
、DELETING
等。此时,状态通常是临时的,会自行转变为另一个状态,无需用户进一步操作。
注意 请记住,只添加对客户有用的状态。没有必要仅仅因为状态在系统内部中存在而发布大量状态,这会给客户带来困惑。每个状态都必须附带一个用例,说明为什么需要它。
只输出域
资源中引用 State
枚举的域 应当 按照AIP-203规定,遵守“只输出域”行为,并记录在文档中。
API 不应 允许通过“更新”方法直接修改(或通过“创建”方法直接设置) State
枚举域, 应当 使用自定义状态转换方法。
这是因为更新方法通常不应具有副作用,直接更新状态意味着可以将状态设置为任何有效值,但状态通常反映资源在生命周期中的进度。
状态转换方法
状态转换方法是一种特殊的自定义方法,负责将状态域从一个枚举值转换到另一个。作为转换工作的一部分,其他域也可能发生变化,例如 update_time
域。方法定义应如下所示:
// 发布书籍。
// 发布后书籍的 state 为 PUBLISHED。
// PublishBook 可以在状态为 DRAFT 的书籍上调用;对于处于不同状态(包括 PUBLISHED)的书籍返回错误。
rpc PublishBook(PublishBookRequest) returns (Book) {
option (google.api.http) = {
post: "/v1/{name=publishers/*/books/*}:publish"
body: "*"
};
}
- 方法的名字 应当 是动词后接资源消息名字的单数形式。
- 请求消息名字 必须 与远程过程调用名字一致,并带有
Request
后缀。 - 应答消息 应当 是资源本身。
- 如果远程过程调用是耗时的,应答消息 应当 是
google.longrunning.Operation
,解析为资源本身。
- 如果远程过程调用是耗时的,应答消息 应当 是
- HTTP动词 必须 是
POST
。 - HTTP URI 必须 使用
:
字符后接自定义动词(如上例中的:publish
)。URI中的动词 必须 与远程过程调用名字中的动词一致。- 如果需要分词, 必须 使用
camelCase
。
- 如果需要分词, 必须 使用
google.api.http
注解中的body
子句 必须 是~"*"~。- 请求消息中接收资源名字的域 应当 映射到URI路径。
- 域 应当 称为
name
。 name
域 应当 是URI路径中唯一的变量。所有其余参数 应当 映射到URI查询参数。
- 域 应当 称为
- 如果不允许请求的状态转换,服务 必须 返回
FAILED_PRECONDITION
(HTTP 400)错误。
请求消息应如下所示:
message PublishBookRequest {
// 要发布的书籍名字。
// 格式:publishers/{publisher}/books/{book}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {
type: "library.googleapis.com/Book"
}];
}
- 必须 包含资源名字域, 应当 称为
name
。 - 域的注释 应当 记录资源模式。
- 可以 包含其他域。
附加指南
默认值
每个状态枚举的零值 应当 遵守以下约定:
enum State {
// 默认值。省略状态时使用此值。
STATE_UNSPECIFIED = 0;
// 其他值...
}
资源 不应 向用户提供“未指定”状态,这个值 不应 实际使用。
值唯一性
同一包中的多个顶级枚举 不得 共享相同的值。这是因为C++ protoc代码生成器将顶级枚举值展平到同一个名字空间中。
状态枚举 应当 存在于资源定义内部。
前缀
不需要在每个枚举值上使用 STATE_
前缀。状态枚举值 不应 以枚举名字作为前缀,默认值 STATE_UNSPECIFIED
除外。
破坏性变更
省流 明确告知用户,状态枚举可能在未来添加新值。向现有枚举添加状态时要谨慎。
尽管向状态枚举添加新状态 可能 破坏现有用户代码,但这不被视为破坏性变更。考虑只有两个值的状态: ACTIVE
和 DELETED
。用户可能会添加代码进行检查 if state == ACTIVE
,并在else情况下简单的假定资源已删除。如果API后来出于其他目的添加了新状态,这份代码将失效。
我们无法从根本上控制这种行为,但API文档 应当 积极鼓励用户在编写代码时假定状态枚举可能在未来添加新值。
API 可以 适时向状态枚举添加新值,并且 不 被视为破坏性变更。
何时避免使用状态
有时 State
枚举可能不是API的最佳选择,特别是状态只有几个可选值或状态不互斥的时候。
考虑前文只有 ACTIVE
和 DELETED
的状态。此时API可能更适合发布 google.protobuf.Timestamp delete_time
域,告诉用户根据域是否设定来判定删除。
常见状态
以下是常用状态列表。API在决定状态名字时 应当 考虑先例。在先例冲突时 应当 优先考虑局部一致性,而非全局一致性。
静置状态
“静置状态”是在没有用户操作的情况下,预计会无限期维持的生命周期状态。用户可以启动操作,将处于静置状态的资源转变为其他状态(静置或活动)。
ACCEPTED
ACTIVE
CANCELLED
DELETED
FAILED
SUCCEEDED
SUSPENDED
VERIFIED
活动状态
“活动状态”是通常会自行转变到一个预期静置状态的生命周期状态。
注意 请记住,只发布对客户有用的状态。只有资源在状态下可能维持足够长的时间,活动状态才有价值。如果状态转变是立即的,不需要活动状态。
CREATING
(通常转变为ACTIVE)DELETING
(通常转变为DELETED)PENDING
(通常转变为RUNNING)REPAIRING
(通常转变为ACTIVE)RUNNING
(通常转变为SUCCEEDED)SUSPENDING
(通常转变为SUSPENDED)
进一步阅读
- 关于枚举的一般信息,请参考AIP-126。
修订记录
- 2022-06-02 修改后缀描述,消除多余的“-”。
- 2020-10-20 添加关于在枚举值前添加枚举名字的指南。
- 2020-09-02 明确状态在创建时也不可以直接设置。
- 2019-12-05 修改状态转换方法指南,将应答类型从 必须 降级为 应当 。
- 2019-08-16 添加状态转换方法指南。
- 2019-07-18 添加关于未指定值的明确指南。