事件传递、幂等性和重复处理
通过网络发送事件会产生生产者可能无法完美观察的结果。在服务器接收请求之前、处理请求时或在接受事件之后但响应到达调用者之前,可能会发生超时。重试可以改善交付,但也可能会创建重复的行。
将交付政策视为活动合同的一部分,而不是附带的 SDK 设置。
给每个逻辑事件一个稳定的身份
知道申请结果后,创建一个 event_id。对于代表相同结果的每次网络尝试重复使用该标识符。不要在重试循环内生成新的标识符。
const eventId = crypto.randomUUID();
const event = {
event_id: eventId,
job_id: job.id,
status: "failed",
error_type: "provider_timeout",
attempt: job.attempt,
};
await sendWithBoundedRetry("job_completed", event);
event_id 可以检测到重复项;它本身并不能保证存储会拒绝每个重复项。如果业务工作流需要一次性效果,请在拥有该效果的系统中强制执行该要求。 Telemetry 应该描述结果,而不是成为支付、权利或数据库突变的交易协调者。
决定哪些失败可以重试
重试临时容量和传输故障,例如连接错误、429、502、503 和 504。当响应提供 Retry-After 时,请尊重它。使用带有抖动的指数退避,并限制尝试次数和总运行时间。
不要重试未更改的 400 请求。无效的 JSON、表名称、字段类型或架构需要更改生产者。替换 401 之后丢失或撤销的凭证;在 403 之后使用具有所需范围的密钥。
速率限制和 API 错误参考 包含响应类和重试规则。
默认情况下,使遥测远离关键路径
对于正常的产品和运营分析,临时遥测故障不应将成功的客户请求变成错误。限制遥测超时,报告安全诊断类别,并根据产品的故障策略继续。
一些工作流程需要更强的交付:
- 用于提供帐单对账的使用记录。
- 批准的控制所需的安全审核事件。
- 不可逆转的业务结果,没有其他事实来源。
对于这些情况,请在业务更改时将结果写入同一事务中的持久应用程序拥有的发件箱。工作人员可以稍后传递事件,同时保留其原始 event_id、发生时间和架构版本。
测量重复和丢失的交付
使用 重复事件 ID SQL 配方 查找具有多个存储行的标识符。按生产者、发布和重试原因分解重复项,以便修复针对实际的交付路径。
还监控:
- 生产者接受和拒绝的事件计数;
- 最早的未送达发件箱记录的年龄;
- 每个逻辑事件的尝试;
- 重试预算后永久失败;
occurred_at和timestamp_utc之间的延迟。
对每个查询进行重复数据删除可以隐藏损坏的生产者。即使下游报告为每个 event_id 选择一行,也可以保持重复率监控可见。
测试不明确的情况
演习成功,明确拒绝,交付前连接失败,服务器可能接受事件后超时。确认重试尝试重用事件 ID,并且应用程序响应遵循记录的失败策略。