想去哪里?

首页 页面 关于 页面 项目 页面 简历 页面 技术 页面 随笔 页面 联系 页面 隐私政策 页面 Terminal Spike 隐私政策 页面 用 Astro 构建文档与职业个人网站 技术 通过 tmux、Mosh、Termius 与 Tailscale 随处使用 Codex 技术 用 Langfuse 观察 Codex 的 MCP 工具调用 技术 产品应用中的本地化 技术 把 MCP 作为安全的 AI 集成边界 技术 用 Zod、OpenAPI 与 Swagger 维护 API 契约 技术 用 pg-boss 运行持久后台任务 技术 通过真实知识工作流理解 pgvector 与 RAG 技术 Pi Edge:让 Pi 待在 Obsidian 笔记旁 技术 为真实排序任务设计拖放交互 技术 Prisma 与 PostgreSQL:产品状态的事实来源 技术 把 Ralph Loop 当作计划队列 技术 用 React Router 组织全栈产品工作流 技术 把 shadcn 风格组件变成自己的产品系统 技术 用表格与编辑器承载密集业务操作 技术 Terminal Spike:原生 Android 终端 技术 在 Linux 上用 fcitx 输入带声调的拼音 技术 在 Linux 上配置 DEFT Pro 轨迹球 技术 在 KOReader 上使用 Pocket 稍后读 技术 为 Vercel AI SDK 设置明确的工具边界 技术 垂直切片架构与 dependency-cruiser 技术 用 Vitest 与 Playwright 测试产品工作流 技术 我的随处工作流:Herdr、code-server、Obsidian 与 Pi Edge 技术 Zod 不只是校验 技术 《卡拉马佐夫兄弟》是我看过最好的小说 随笔 基督徒口述1960劳改历史 随笔 圣经中的“道”与言语 随笔 我们爱,因为神先爱我们,而不是空洞的“自爱” 随笔 妈妈,让我来承担爸爸的过错吧 随笔 我与神的故事 随笔 世界远离上帝,接近中国 随笔 “爱的五种语言”和内外向,只存在于语言中 随笔 人格类型不存在,你在世界而非概念中生活 随笔 危险的词语:为什么心理学是不可能的 随笔 2000 年,一个深圳打工者的故事 随笔 阿联酋Ras al Khaimah见闻录 随笔 沙甸:1975 年的一场冲突 随笔 关于中国的纪录片 随笔
← 技术/工程实践

用 pg-boss 运行持久后台任务

将缓慢的产品流程放入数据库任务队列,以及用户需要看到什么。

客户的问题并不是“我们需要队列”,而是操作很慢,用户等待时得不到明确答复。

队列只是实现细节,产品问题是无法确定发生了什么。用户点下按钮,应用长时间没有回应,没人知道工作是否启动、失败,还是稍后会完成。

对于报表导出、CSV 导入等流程,我倾向将慢操作移到持久后台任务中。网页请求做基础校验、创建任务,再带用户进入状态页,由 worker 处理耗时部分。

await boss.send("report.export", {
  reportId,
  requestedBy: userId,
  idempotencyKey,
});

任务名与载荷是示意,但结构贴近实际:请求留下足够的信息供稍后执行,用户得到一个可追踪的任务。

我喜欢在这个阶段使用 pg-boss,因为它基于 PostgreSQL。应用已经用 Postgres 保存持久状态时,数据库队列能避免过早增加单独的队列服务。

状态页是关键界面。用户需要理解排队、运行、完成、失败等状态:

queued
running
done
failed

用户与支持人员都不用再猜按钮是否生效,系统有任务记录和最新状态。

重试只有在任务能承受重复执行时才有用。它不应造成重复记录、重复邮件或重复扣款。幂等键让 worker 知道“这个逻辑请求已经处理过”。

失败也需要产品层面的答案,不能只消失在工程师才能看懂的日志里。用户可能需要简短错误说明、重试按钮或下载校验错误的入口。具体界面取决于流程,但失败状态必须设计。

队列不会消除复杂性,只是转移它。你仍需维护 worker、监控、重试策略及部署过程中的行为。相比把长任务塞进一个请求让用户等待,这通常更合理,但并非没有成本。

应用已使用 PostgreSQL、任务量适中、重视运维简单且不想增加独立队列服务时,我会选择 pg-boss。任务吞吐成为瓶颈、worker 需要特殊扩缩容,或已有队列基础设施时,则考虑独立队列。

后台任务也是产品功能。队列重要,但用户看得见的流程更重要。持久任务没有清楚的状态页,用户依然只能猜。