系统设计
队列也是 API 契约的一部分
把工作放进队列会改变延迟、责任归属和故障语义,但不会让这些问题消失。
收到请求不等于完成任务
HTTP 202 Accepted 表示服务器已接受任务,并承担尝试执行它的责任。这不代表任务已经成功,甚至不代表工作线程已经开始处理。
客户端需要一个持久的任务标识,以及清楚易懂的状态信息:
{
"job_id": "job_7f31",
"state": "queued",
"status_url": "/jobs/job_7f31"
}重试会产生重复任务
工作线程可能已经完成副作用,却在确认消息前崩溃。于是队列会再次投递同一条消息。这就是普通的至少一次投递,并非罕见的边缘情况。
使用幂等键、数据库唯一约束,或可以安全重复执行的状态转换。应在提交副作用的位置保证这一不变量。
背压是一项产品决策
没有上限的队列只会把过载转化为延迟故障。设置容量限制、公布队列等待时间,并决定系统无法继续处理时要拒绝什么。今天清楚地返回 429 或 503,往往比明天悄悄完成一个已经过期的任务更友好。
队列属于 API 的一部分,因为队列语义最终会成为客户端感受到的语义。请在接口文档中写清楚。
