Sign inGet Started

幂等性

网络总在最糟糕的时刻出故障:你 POST 了一个发送请求,连接断开,此时你不知道邮件是否已发出。幂等性让你可以安全地重试该请求。再次发送相同的 Idempotency-Key 请求头,Bird 会重放原始响应,而不会再次处理该请求。

工作原理

幂等性是可选启用的。在支持的 POST、PATCH、PUT 或 DELETE 请求中添加 Idempotency-Key 请求头。未携带该请求头的请求将正常处理,不进行去重。GET 请求会忽略该请求头。
在客户 API 上,工作区级和组织级的变更操作支持下文所述的响应重放。仅限用户的操作、无作用域的未认证操作以及流式操作不受此机制影响。具有独立重放契约的操作会在其参考页面中定义自身行为。例如,创建语音通话在您提供密钥时会保留原始接受快照,用于匹配重试。
SDK 会为每个变更调用生成一个密钥,并在自动重试(包括创建通话)时复用该密钥。自动 SDK 重试无需您提供密钥。当一个预期操作跨越多次独立的 SDK 调用时(例如重启应用后的重试),请提供您自己的密钥。以下示例展示的就是这种场景。
await bird.email.send(
  {
    from: "hello@yourdomain.com",
    to: ["delivered@messagebird.dev"],
    subject: "Welcome!",
    html: "<p>Thanks for signing up.</p>",
  },
  { idempotencyKey: "welcome-user/usr_abc123" },
);
密钥可以是任何非空字符串,最长 255 个字符。空的请求头值会跳过去重。推荐的格式是从您自身实体派生的确定性密钥,<event-type>/<entity-id>(例如 welcome-user/usr_abc123),这样跨进程重启的重试可以共享同一个密钥;每个逻辑操作使用一个随机 UUID 也可以。Bird SDK 会为每个变更请求自动生成 UUID 密钥,并在其内部重试中复用。
键的作用域为你的工作区,或在组织级别端点上为你的组织。已完成的响应会保留 3 小时;超过该窗口后的重试将作为新请求处理。该窗口涵盖了典型的重试调度周期。过期后不会保留任何去重记录。

重放

当 Bird 发现某个键已经完成处理时,它会返回缓存的响应,状态码和响应体与原始响应完全一致,不会重新执行请求。重放的响应会携带一个额外的请求头,方便你区分它与首次处理的响应:
代码示例
HTTP/1.1 202 Accepted
Idempotency-Replay: true
保留的响应可能包含 4xx 拒绝。纠正请求时请使用新键:如果该拒绝已被保留,未更改的重试会重放该拒绝,而更改后的请求则返回 409 E01005 IdempotencyKeyReuse。5xx 响应不会被保留,因此请使用相同的键和请求进行重试。

失败场景

场景响应
相同键、相同请求,原始请求已完成缓存的响应通过 Idempotency-Replay: true 重放
相同键、不同的请求体或端点409,E01005 IdempotencyKeyReuse
相同键,原始请求仍在处理中409,E01004 RequestInProgress
键超过 255 个字符,且端点声明了该请求头422、E01001 ValidationError
幂等保护在执行前不可用503,E01033 IdempotencyUnavailable;此次尝试未被执行
使用已完成的键发送不同的请求会被视为客户端 bug:Bird 会立即返回 409,而不是静默地返回一个与您发送内容不匹配的响应。请为新请求生成新键。比较范围涵盖方法、端点、路径和查询参数以及原始请求体,包括 JSON 空白字符。多部分上传会比较部分名称、文件名和内容;边界和部分顺序不影响重放。
RequestInProgress 表示使用相同键的并发请求尚未完成,通常是因为客户端超时过于激进,在第一次尝试仍在处理时就发起了重试。处理中的锁会在 30 秒内过期,因此请稍等片刻后重试。参见错误了解这些错误所包含的错误响应格式。

不会被缓存的内容

5xx 响应永远不会被缓存。 键会解锁,Bird 可以将重试作为新的尝试来处理。使用相同的键和请求,以退避策略重试 5xx 响应和超时。操作可能在其响应被保留之前就已生效;如果该响应丢失,或处理中的锁过期,重试可能会再次执行该操作。
如果幂等性保护在执行前不可用,API 会返回 503 E01033 IdempotencyUnavailable,且不会执行此次尝试。每次重试都应保留该键。此错误不描述使用相同键的先前尝试的结果。

实践指南

  • 为每个逻辑操作生成一个键,并在该操作的每次重试 HTTP 尝试中复用它。
  • 在网络错误、超时和 5xx 时使用指数退避进行重试,每次复用相同的键。
  • 将 409 IdempotencyKeyReuse 视为键生成中的错误,不要重试。
  • 密钥在变更操作中是可选的。需要重试保护时使用密钥;在 GET 请求中可以省略。

后续步骤