异步、队列、Webhook 与定时任务
长任务如何排队、事件如何主动通知、任务如何定时触发。
一句话理解:不是所有事都能“问一句、马上答”:慢的任务放进队列排队做,外部事件用 Webhook 主动通知,周期性的工作交给定时任务触发。
Agent 的很多工作天然是“慢”的:分析一个季度的销售数据要几分钟,Coding Agent 修复一个复杂 Bug 可能要半小时,订单售后诊断要等支付平台回传对账结果才能继续。如果把这些任务都设计成“用户发请求 → 一直转圈等结果”,要么浏览器超时断开,要么用户盯着屏幕干等,要么服务器被大量挂起的请求拖垮。
这一课介绍四个让系统“不必干等”的基础机制。它们是长时间运行的任务与异步任务体验的技术底座。
同步与异步:打电话与发消息
| 方式 | 类比 | 调用方的状态 | 适合 | 例子 |
|---|---|---|---|---|
| 同步 | 打电话,对方不挂你就一直等 | 阻塞等待结果 | 秒级完成的操作 | 查一个订单的状态 |
| 异步 | 发消息,对方处理完再回复 | 提交后可以去做别的事 | 耗时长、可能失败需重试的操作 | 生成月度销售分析报告 |
一个典型的异步接口交互:
POST /v1/reports HTTP/1.1
Content-Type: application/json
{ "type": "sales_decline_analysis", "region": "华东", "period": "2026-08" }
HTTP/1.1 202 Accepted
Content-Type: application/json
{ "job_id": "job_7f3a", "status": "queued", "status_url": "/v1/jobs/job_7f3a" }
注意状态码是 202 Accepted:“已收到,还没做完”。之后调用方有两种方式拿结果——自己去问(轮询),或者 等对方通知(Webhook)。
队列:让任务排队,而不是挤爆系统
队列(Queue)是一个“待办箱”:生产者把任务放进去,一个或多个消费者(Worker)按顺序取出来处理。
队列解决了几个问题:
| 问题 | 没有队列 | 有队列 |
|---|---|---|
| 突发流量 | 1000 个分析请求同时打进来,服务崩溃 | 请求排队,Worker 按能力处理 |
| 下游限流 | 模型 API 限流导致大量失败 | 控制并发数,平稳消费 |
| 失败重试 | 失败了就丢失 | 自动重试,多次失败进入“死信队列”待排查 |
| 用户体验 | 用户一直等待 | 立即返回“已提交”,完成后通知 |
对 Agent 来说,队列还有一个特别的价值:模型 API 通常有速率限制,批量任务(例如给 5000 个商品页面做 SEO 诊断)必须通过队列控制并发,否则大量请求会收到 429。
轮询与 Webhook:怎么知道任务做完了
轮询(Polling):调用方每隔一段时间去问一次。
Agent:job_7f3a 好了吗? → 系统:running
(等 10 秒)
Agent:job_7f3a 好了吗? → 系统:running
(等 10 秒)
Agent:job_7f3a 好了吗? → 系统:done,结果在这里
Webhook:调用方事先留下一个地址,事件发生时由对方主动发请求过来。
POST /webhooks/payment HTTP/1.1
Host: agent.example.com
Content-Type: application/json
X-Signature: sha256=5d41402abc4b2a76...
{
"event": "payment.status_changed",
"event_id": "evt_20260917_0001",
"order_no": "A1234",
"event_type": "exception",
"description": "扣款成功但订单未收到回调",
"occurred_at": "2026-09-17T10:05:00+08:00"
}
| 维度 | 轮询 | Webhook |
|---|---|---|
| 谁主动 | 调用方反复询问 | 事件方主动推送 |
| 实时性 | 取决于轮询间隔 | 事件发生后很快送达 |
| 资源消耗 | 大量“还没好”的无效请求 | 只在事件发生时通信 |
| 实现难度 | 简单 | 需要一个公网可访问的接收地址 |
| 可靠性问题 | 间隔太长则延迟高 | 可能丢失、重复或乱序送达 |
两种方式的通信过程对比如下:
Webhook 的三个必做事项:
- 验证签名:上面的
X-Signature用来确认请求确实来自支付平台,而不是有人伪造“订单已支付”的消息。 - 幂等处理:同一事件可能被发送多次,用
event_id去重,避免同一异常创建两张工单。 - 快速响应、异步处理:收到后先返回 2xx,再把事件放进队列慢慢处理,否则对方可能判定超时并重发。
定时任务:让 Agent 按时上班
定时任务(Cron Job)在固定时间自动触发。Cron 表达式常见格式是 5 个字段:
┌───────── 分钟 (0–59)
│ ┌─────── 小时 (0–23)
│ │ ┌───── 日 (1–31)
│ │ │ ┌─── 月 (1–12)
│ │ │ │ ┌─ 星期 (0–6,0 为周日)
│ │ │ │ │
0 9 * * 1 每周一 09:00
*/30 * * * * 每 30 分钟
0 2 1 * * 每月 1 日 02:00
不同平台对字段数、时区的约定可能不同(有的默认 UTC),配置时务必确认时区。
把四个机制组合进 Agent 场景
| 场景 | 触发方式 | 执行方式 | 结果交付 |
|---|---|---|---|
| 每周一 SEO 诊断报告 | 定时任务 0 9 * * 1 |
放入队列,Agent 执行诊断 | 生成报告后发到群里 |
| 订单异常实时处理 | 支付平台 Webhook 推送异常事件 | 事件入队,Agent 逐个分析 | 创建工单,高风险项等人确认 |
| 用户发起销售下滑分析 | 用户点击按钮 | 返回任务 ID,Agent 在后台运行 | 完成后站内通知 + 邮件 |
| 批量诊断 5000 个页面 | 用户上传列表 | 拆成 5000 个任务入队,限制并发 | 进度条 + 汇总报告 |
把订单异常场景画完整:
最后一行值得注意:Webhook 不保证 100% 送达,重要的业务通常会用定时扫描做兜底。这种“事件驱动 + 定时补偿”的组合在生产系统中非常常见。
常见误区
- “Agent 任务就应该让用户在对话框里等着。” 超过几十秒的任务就该考虑异步:立即反馈“已开始”,完成后通知,用户可以离开页面。
- “收到 Webhook 就直接处理。” 不验签可能被伪造,不去重会重复处理,处理太慢会被对方重发。
- “失败了自动重试就行。” 重试需要上限和退避间隔;对会产生副作用的动作(发通知、建工单),重试前必须有幂等保护。
产品经理检查清单
- 这个 Agent 任务通常耗时多久?是否需要异步执行?
- 任务提交后,用户看到什么?能否离开页面?完成后通过什么渠道通知?
- 用户能否查看进度、取消任务?
- 触发来源是用户操作、外部事件还是定时?
- 外部事件是否有签名验证与去重机制?
- 失败后重试几次?最终失败时谁来处理?
- 批量任务的并发上限是多少?是否考虑了模型 API 与业务系统的限流?
- 定时任务的时区是否明确?有没有补偿机制防止漏处理?
练习
用 45 分钟为“每周 SEO 诊断 Agent”设计异步方案:
- 写出 Cron 表达式:每周一北京时间早上 8 点运行。
- 画出流程:定时触发 → 拆分任务 → 队列 → Agent 执行 → 汇总 → 通知。
- 回答三个问题:
- 如果其中 30 个页面抓取失败,报告应该怎么呈现?
- 如果上周的任务还没跑完,这周的又触发了,怎么办?
- 用户想临时手动触发一次,入口放在哪里?
下一步
队列里的 Agent Worker,很多是在终端里跑命令、在代码仓库里干活的。下一课「命令行与 Git」带你走进 Coding Agent 的主战场。