2026-09-27·by Sijie Wang#standmeet#architecture#design#events

completion-hooks

完结 hook:任务终态发一条通知

上级:events

状态: 已在 v0.1.76 发布(2026-09-27)—— 设计与落地记录见 StandMeet 仓库的 docs/design/event-bus-outbox-webhooks.md。

任何任务进入终态都发一条 Postgres 通知。原来等同步结果的调用方,改为等这条通知,等到上限就给回执。业务状态跟着完结走,不跟着入队走。

谁在等,现在拿到什么

查了代码:要搬的 13 类操作里,有 4 个的调用方在等结果,变异步后都需要完结信号。

操作原来谁在等实现后的完结信号
批准申请的带码邮件后台显示“已发送给申请人”或报错;MCP access_requests.approve 返回结果码同步签发,access_request.approval_mail 任务在同一事务里入队(mail_job_id)。该行显示 request-mail-state:发送中、已发送或失败。发送成功后才标记“已回复”(经 UpdateAccessRequestStatus)。MCP 最多等 2 秒,然后给回执。
换邮箱确认邮件提示“确认邮件已发到 X”pending 行同步写入并带 pending_email_job_id;提示改为“已排队”;pending 行上显示发送状态。owner.email_confirmation 任务在发送时才生成链接令牌,过期的任务什么都不发。
jobs.fetch_newMCP 直接返回抓到的职位列表;后台等请求返回每个职位源一个 jobs.fetch_source 任务。MCP 最多等 20 秒,跑完就返回列表;否则返回 {job_ids, pending: true}。jobs.fetch_result {job_ids} 返回完整形状;tasks.get 只给状态。
访客侧检索(Meili)写后即读retrieval-search-consistency.spec.ts 断言写完就能搜到corpus.create、corpus.update、corpus.promote 的回执带 indexed 和 index_job_id;请求内最多等 2 秒(见 async-response-contract)

其余没人在等:访客申请通知、预约通知、补偿删除、Obsidian 重建、构建后钩子、启动回填。恢复短语邮件也在等结果,已定案保持同步。

机制:终态是一条通知,不是事件

  • 任务进入 completed、discarded 或 cancelled 时发 pg_notify('standmeet_job_final', 任务 id)。
  • 每个进程一条共享的 LISTEN 连接(pgstore.Listener)唤醒等这个 id 的等待者。同时最多 64 个等待者,超了调用方立刻拿回执。
  • 没有 job.completed / job.discarded 这类 outbox 事件。每个任务记一条,就会为每个任务再扇出一遍。任务行本身是面板和 tasks.get 读取的持久记录。
  • UI 状态标签目前轮询任务状态(P5 换 SSE)。
  • 请求会等的队列(index、notify)每 100 毫秒轮询一次。等待者通常在这次轮询加 River 250 毫秒的完结批次内拿到结果(concurrency-control)。
  • 业务状态跟着完结走:“已回复”这类状态由任务 handler 在发送之后写,不在发送前写。

已更新的现有 spec

原则:只改“什么时候看”,不改“看到什么”——同步断言改成等待或轮询,断言的结果不变。

  • 批准与邮件:mail-supplier、mail-throttle-recipient、admin-requests(没配邮件时返回 400 这条保持同步)、access-request-notifies-owner(精确计数改为等终态)。
  • 换邮箱 / 恢复:account-email-change-needs-confirmation、account-email-pending-lifecycle、account-recovery-row-tells-the-truth、account-edit。
  • 检索:retrieval-search-consistency,并复查了 retrieval-acl、corpus-grep、subjectivity-not-cited、corpus-search-cjk-not-silent。
  • 招聘抓取:job-fetch-*、integration-job-loop、application-status-persist、admin-listings-dedup。
  • booking-owner-notify:等到终态再断言数量。
  • norm-outward-toolset 的 golden 加上了 tasks.*、events.*、webhooks.* 和 jobs.fetch_result 工具。

任务面板的 e2e(tasks-panel-more)覆盖这些:批准申请后行状态从“发送中”变“已发送”;mail mock 先失败时显示“失败”,重试后变“已发送”;jobs.fetch_new 超过等待上限时返回回执,jobs.fetch_result 返回同形状的结果(events-test-plan)。

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →

completion-hooks