Communitygithub.com

背景任務佇列設計

設計背景任務佇列系統時使用,協助選擇 BullMQ / Sidekiq / RQ / Temporal / SQS 等工具,並解決重複執行、遺失任務、重試風暴等常見問題。

背景任務佇列設計 是什麼?

此技能提供一個完整的參考指南,協助開發者設計可靠、可擴展的背景任務佇列系統。它涵蓋了從一開始就必須考慮的三種失敗模式:任務遺失、重複執行和無節制的重試。技能深入比較了 BullMQ、Sidekiq、SQS 和 Temporal 等不同佇列系統的適用場景,並提供了關於冪等性(Idempotency)、可靠提取(Reliable Fetch)、可見性超時(Visibility Timeout)、死信佇列(DLQ)管理、指數退避與抖動(Backoff & Jitter)、並發控制與限流(Concurrency & Limiter)以及記憶體管理(Memory Hygiene)等核心能力的實作模式和最佳實踐。它還是一個決策輔助工具,清晰區分何時應使用簡單佇列,何時應採用如 Temporal 這樣的持久化執行工作流程。此技能支援 Node、Ruby、Python 與 Go 等語言,並廣泛引用 BullMQ、Sidekiq 與 AWS 的官方文件。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/curiositech/windags-skills/tree/HEAD/skills/background-job-queue-design

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

背景任務佇列設計 是做什麼的?

一個背景任務系統從第一天起就必須針對三種失敗模式進行設計:任務遺失、重複執行和無節制的重試。選錯基礎元件,你可能要花費接下來一整年的時間來解決這三個問題。在 BullMQ、Sidekiq、SQS 和 Temporal 的文件中反覆出現的業界共識是:至少一次 (at-least-once) 是唯一誠實的投遞語意 — 讓每個處理器都具備冪等性 (idempotent),並停止追尋「恰好一次」(exactly-once)。(Caduh — Queues 101)

快速跳轉到你的問題:

何時使用

  • 在 Node、Ruby、Python 或 Go 中設計一個新的背景任務系統。
  • 從 setTimeout / cron / 自製佇列遷移到真正的訊息代理 (broker)。
  • Worker 崩潰導致任務遺失。
  • 生產環境中的重試導致重複的副作用。
  • 在 BullMQ (Node + Redis)、Sidekiq (Ruby + Redis)、RQ / Celery / Dramatiq (Python)、Asynq (Go + Redis)、SQS (託管式) 或 Temporal (持久化執行) 之間做選擇。

核心能力

選擇符合工作的基礎元件

你擁有的是選擇原因
Node 上的短暫、有副作用的任務 (發送郵件、調整圖片尺寸)BullMQ原生支援 Redis,成熟的 DLQ,流程模式,單節點典型吞吐量 ~5k 任務/秒
Ruby 上的相同情況Sidekiq (Pro 版本以獲得可靠性)相同架構;Pro 版本的 super_fetch 透過 LMOVE 指令提供可靠提取 (Sidekiq wiki)
需要外部 API 扇形展開 (fan-out)、持續數小時到數天的多步驟工作流程Temporal持久化執行;從事件歷史中重播 (Temporal docs)
AWS 原生環境、簡單的扇形展開、不想運行 RedisSQS + Lambda託管式「至少一次」語意;內建可見性超時和 DLQ (AWS SQS DLQ)
跨區域、多租戶隔離Temporal 或 SQS單一 Redis 無法乾淨地支撐多區域場景
需要在資料庫、郵件和支付之間實現「恰好一次」都不要 — 設計「至少一次」+ 冪等處理器代理內部的「恰好一次」無法跨系統延伸 (Caduh)

隱藏的判斷標準:復原故事的複雜度為何? 一個帶有重試機制的簡單 BullMQ 佇列足以處理「發送收據」任務。一個包含 12 個步驟、需要暫停 24 小時等待 Webhook 的購買工作流程,是一個 Temporal 工作流程,而不是 12 個鏈接的佇列任務。

冪等性

這是必須強制執行的屬性。每個流行的佇列文件都會首先提到這一點。來自 BullMQ 的冪等任務頁面:「任務無論是在第一次嘗試就成功完成,還是初始失敗後重試成功,都不應對系統的最終狀態產生影響。」(BullMQ idempotent-jobs)

實用模式:

// 1. 冪等性金鑰應源自業務事件,而非佇列本身。
//    如果有上遊 event_id (例如 Stripe event.id, Shopify hook id),請使用它。
const job = await queue.add(
  'send-receipt',
  { orderId, amount },
  {
    jobId: `send-receipt:${orderId}`,   // BullMQ 根據佇列中的 jobId 進行去重。
    attempts: 5,
    backoff: { type: 'exponential', delay: 1000 },
    removeOnComplete: { age: 3600, count: 1000 },
    removeOnFail:     { age: 86400 },
  }
);

// 2. 在處理器內部,也應在副作用發生的位置進行去重。
async function processSendReceipt(job) {
  const { orderId, amount } = job.data;
  // 如果已經發送過,就不做任何事。
  const sent = await db.queryOne(
    'INSERT INTO email_sends (idempotency_key, order_id) VALUES ($1, $2) ON CONFLICT DO NOTHING RETURNING id',
    [`send-receipt:${orderId}`, orderId]
  );
  if (!sent) return { skipped: 'already-sent' };
  await emailProvider.send({ to: ..., subject: ..., body: render(amount) });
}

jobId 可以在重複任務仍處於佇列中時防止重複添加。資料庫的唯一約束則可以防止跨 Worker 崩潰、重試和重播時的副作用重複。兩者都是必需的;僅靠 jobId 是不夠的,因為 BullMQ 會移除已完成的任務,導致去重的視窗消失。

可靠提取與可見性超時

當一個 Worker 拉取任務後崩潰時,會發生什麼事?

系統預設行為復原機制
BullMQ任務有 lockDuration (預設 30 秒)。過期後,停滯任務檢查器會將其重新排入佇列 (BullMQ production)Worker 必須在 lockDuration 內延長鎖定或完成任務;否則任務會被執行兩次
Sidekiq OSS彈出操作 (POP) 非原子性;如果 Worker 在彈出和處理之間死亡,任務會遺失升級到 Sidekiq Pro 的 super_fetch (Redis 6.2+ 使用 LMOVE 移到私有的工作佇列)
Sidekiq Pro super_fetch使用 LMOVE 移到每個行程的處理清單。心跳在 60 秒後過期;孤兒檢查會掃描並重新排隊 (Sidekiq wiki)內建
SQS可見性超時 (預設 30 秒,最長 12 小時)。如果未刪除,訊息會在超時後重新出現設定超時時間 > 處理器的 p99 延遲;對於長時間任務,使用 ChangeMessageVisibility 進行延長
Temporal活動 (Activity) 具有心跳和重試策略。工作流程歷史在 Worker 死亡後依然存活從歷史重播;你無需考慮這個問題

陷阱:lockDuration / 可見性超時短於處理器的 p99 延遲 → 任務會執行兩次。時間長於可接受的復原時間 → 崩潰的工作會等待太久。請先測量你的 p99,將超時時間設定為約 p99 的 3 倍,並讓長時間運行的處理器透過心跳來延長鎖定。

錯誤分類與死信佇列

並非所有錯誤都應該無限期重試。根據 SQS 文件:「設定最大接收次數... 和重新驅動策略,以便在超出閾值時將訊息發送到 DLQ。」(AWS SQS DLQ)

// 在拋出前進行分類。永久錯誤不應重試。
class PermanentError extends Error { constructor(m: string) { super(m); this.name = 'PermanentError'; } }
class TransientError extends Error { constructor(m: string) { super(m); this.name = 'TransientError'; } }

async function process(job) {
  try {
    const user = await db.user(job.data.userId);
    if (!user) throw new PermanentError('user-not-found');   // → 立即進入 DLQ
    if (user.suspended) throw new PermanentError('user-suspended');
    await externalApi.call(user);
  } catch (e) {
    if (e instanceof PermanentError) {
      // 立即移至 DLQ — 重試無濟於事。
      job.discard();    // BullMQ: 防止重試
      throw e;
    }
    throw e;            // 網路/超時錯誤 → 根據重試策略重試
  }
}

DLQ 還需要:

  • 一個針對數量增長的警報 (不僅僅是非零 — 「DLQ 永遠有 3 個東西」沒問題;「DLQ 每分鐘增長 100 個」是火警)。
  • 一個重播工具 (CLI 或管理員 UI),讓人類操作員修復上遊錯誤、重播死信任務並清空 DLQ。
  • 儀表板 (參見 grafana-dashboard-builder)。

退避與抖動

僅靠指數退避是不夠的。如果 1000 個任務都在 12:00:00 因為下游服務短暫故障而失敗,純指數退避會導致所有 1000 個任務分別在 12:00:01、12:00:03、12:00:07 同時重試 — 這形成了一個「驚群效應」(thundering herd),可能會讓正在恢復的下游服務再次癱瘓。請加上全抖動 (full jitter):

// AWS 風格的「全抖動」: delay = random(0, exp_backoff)
const baseDelay = Math.min(2 ** attempt * 1000, 30_000);
const delay = Math.random() * baseDelay;

對於 BullMQ 推薦的基線設定,going-to-production 文件建議使用 retryStrategy 將重試間隔設定在 1 秒到 20 秒之間。(BullMQ production)

並發與限制器

每個 Worker 的並發設定允許從單個行程中並行運行 N 個任務。多個 Worker 會放大這個數字。如果沒有佇列級別的限制器,你無法限制對下游的聚合呼叫量:

// BullMQ — 對這個佇列上的所有 Worker 進行全局速率限制。
const queue = new Queue('outbound-emails', {
  connection,
  limiter: { max: 100, duration: 1000 }, // 每秒最多 100 封郵件,跨整個服務集群
});

正確的形態:大量的並發 Worker + 一個用於遵守下游合約限制的佇列限制器。Sidekiq 有等效的速率限制器;SQS 則使用 Lambda 並發數或每訊息速率來控制。

記憶體衛生

BullMQ 生產環境中最被強調的一個陷阱是:將 Redis 實例的 maxmemory-policy 設定為 noeviction。任何其他策略 (allkeys-lru, volatile-lru) 都會在記憶體壓力下默默地逐出排隊中的任務。(BullMQ production)

此外:

  • 積極地設定 removeOnComplete (例如 { age: 3600, count: 1000 })。
  • 一旦你開始使用 DLQ 模式,對 removeOnFail 可以設定得更為積極。
  • 啟用 Redis AOF 持久化 — appendfsync everysec 是 BullMQ 文件中提到的甜蜜點。(BullMQ production)
  • Worker 設定 maxRetriesPerRequest: null 以防止 ioredis 在短暫斷線時拋出錯誤。(BullMQ production)
  • 生產者端:設定 enableOfflineQueue: false,讓生產者在無法連接時快速失敗,而不是緩衝請求。

優雅關機

process.on('SIGTERM', async () => {
  await worker.close();   // 停止接受新任務;等待正在執行的任務完成。
  await connection.quit();
  process.exit(0);
});
process.on('SIGINT', async () => { /* 相同 */ });

BullMQ 的生產環境指南明確指出:在停止行程前先關閉 Worker;預設的停滯超時約為 30 秒。(BullMQ production)

佇列 vs 工作流程決策

來自 Temporal 文件的有用框架:「與訊息佇列在服務之間傳遞資料不同,Temporal 編排整個流程... 知道你處於工作流程的哪個位置、哪些已完成、哪些待處理、哪些需要重試。」(Temporal blog)

flowchart TD
  A[背景工作] --> B{單一副作用還是管道?}
  B -->|單一| C[BullMQ / Sidekiq / SQS]
  B -->|多步驟| D{步驟耗時數秒還是數小時以上?}
  D -->|數秒| E[BullMQ flows / Sidekiq batches]
  D -->|數小時以上或需要人工介入| F[Temporal / DBOS / Restate]
  C --> G{需要跨區域或多租戶隔離?}
  G -->|是| H[SQS 或 Temporal — 單一 Redis 叢集無法滿足]
  G -->|否| I[使用 Redis 叢集 + AOF + noeviction]

反模式

僅透過 Redis SET-NX 實現冪等性

症狀:在 Redis 短暫故障或重啟期間,同一個任務被執行兩次,並產生重複的副作用 (扣款、郵件、工單)。 診斷:Redis 是一個快取;它可能被逐出、重啟或發生分區。僅存在於 Redis 中的 SET-NX 去重機制是「盡力而為」的。 修復:在副作用記錄 (例如 email_sends.idempotency_key) 上使用資料庫唯一約束來實現冪等性金鑰。創建副作用的資料庫事務本身就是去重的基本單元。

lockDuration 短於處理器 p99

症狀:出現停滯任務日誌條目;同一個任務被兩個 Worker 處理。客戶投訴。 診斷:預設的 lockDuration 為 30 秒;處理器有時需要 45 秒;第二個 Worker 會撿起這個任務。 修復:測量 p99,將 lockDuration 設定為約 p99 的 3 倍,並在長時間處理器中呼叫 job.extendLock()。或者拆分任務。

純指數退避 (無抖動)

症狀:下游系統的短暫故障變成了下游系統的全面中斷;10k 個任務以鎖步方式衝擊正在恢復的服務。 診斷:沒有抖動,重試時間是相關聯的。 修復:使用全抖動退避。限制最大延遲以限制 DLQ 的失敗時間。

Redis 使用了 maxmemory-policy allkeys-lru

症狀:佇列在負載下神秘地遺失任務。沒有任何錯誤。(BullMQ production) 診斷:Redis 為了騰出空間而逐出了任務金鑰。 修復:執行 CONFIG SET maxmemory-policy noeviction 並在啟動時檢查此設定。Worker 應拒絕在違反此設定的環境中啟動。

假裝跨系統存在「恰好一次」

症狀:同一個客戶被扣款兩次;發送了兩封相同的郵件。工程師堅信「代理是『恰好一次』的。」 診斷:即使是一個 FIFO/恰好一次的代理,也無法將其保證延伸到你的資料庫、郵件服務商、Stripe 和帳本。 修復:將佇列視為「至少一次」。在每個副作用邊界實施冪等性。

DLQ 沒有重播工具

症狀:「我們 DLQ 裡有 3,200 個任務。我們不知道裡面有什麼。」DLQ 變成了一個無人監控的墳場。 診斷:建立了 DLQ,但沒有建立運維工具。 修復:提供按 ID 重播、按時間範圍重播、確認後清空等功能。CLI 或管理員 UI。需要經過測試。

在事件循環中執行長時間阻塞的工作

症狀:BullMQ Worker 行程無回應;心跳停止;鎖定過期;任務重新執行。 診断:在與佇列心跳相同的行程中執行 CPU 密集型工作;事件循環阻塞時間超過 lockDuration。 修復:為 CPU 密集型工作建立子行程或 Worker 執行緒。或者運行一個沙箱處理器 (BullMQ 支援每個任務的行程沙箱)。

品質檢查清單

  • 測試: 混沌測試 — 在任務處理中途殺死 Worker;斷言任務會重新執行且副作用不會重複。
  • 測試: 重試風暴測試 — 讓下游系統故障 60 秒;斷言退避 + 抖動分散了重試 (監控指標中沒有驚群效應)。
  • 每個處理器都是冪等的,並使用源自業務事件的穩定冪等性金鑰。
  • 存在資料庫級別的唯一約束來備份任何存在於 Redis 中的去重機制 (jobId, SET-NX)。
  • lockDuration / 可見性超時 ≥ 3 × 測量到的處理器 p99 延遲,並且長時間處理器會延長鎖定。
  • 永久錯誤 (PermanentError 類或等效物) 繞過重試,直接進入 DLQ。
  • DLQ 警報:當增長速率 > N/分鐘時觸發頁面通知,而不僅僅是計數 > 0。
  • DLQ 重播工具存在且已測試 (單個 + 範圍)。
  • Redis:maxmemory-policy=noeviction,已啟用 AOF (appendfsync everysec),並在 Worker 啟動時檢查。(BullMQ production)
  • 已設定 removeOnComplete 和 removeOnFail。任務計數指標已在監控中顯示趨勢。

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

curiositech/windags-skills

Expert in 2000s-era music visualization (Milkdrop, AVS, Geiss) and modern WebGL implementations. Specializes in Butterchurn integration, Web Audio API AnalyserNode FFT data, GLSL shaders for audio-reactive visuals, and psychedelic generative art. Activate on "Milkdrop", "music visualization", "WebGL visualizer", "Butterchurn", "audio reactive", "FFT visualization", "spectrum analyzer". NOT for simple bar charts/waveforms (use basic canvas), video editing, or non-audio visuals.

curiositech/windags-skills

Expert legal research agent for finding and scraping expungement data state by state. Knows authoritative sources, URL patterns, Firecrawl configuration, and 2026 legal landscape.

curiositech/windags-skills

Expert in 3D computer vision labeling tools, workflows, and AI-assisted annotation for LiDAR, point clouds, and sensor fusion. Covers SAM4D/Point-SAM, human-in-the-loop architectures, and vertical-specific training strategies. Activate on '3D labeling', 'point cloud annotation', 'LiDAR labeling', 'SAM 3D', 'SAM4D', 'sensor fusion annotation', '3D bounding box', 'semantic segmentation point cloud'. NOT for 2D image labeling (use clip-aware-embeddings), general ML training (use ml-engineer), video annotation without 3D (use computer-vision-pipeline), or VLM prompt engineering (use prompt-engineer).

curiositech/windags-skills

Implement WCAG 2.2 AA/AAA compliance with automated testing, keyboard navigation, screen reader support, and focus management. Activate on: accessibility audit, WCAG compliance, keyboard navigation, screen reader, aria attributes, axe-core, focus trap. NOT for: design-level accessibility review (use design-accessibility-auditor), color contrast only (use css-in-js-architect).

curiositech/windags-skills

Time-blind friendly planning, executive function support, and daily structure for ADHD brains. Specializes in realistic time estimation, dopamine-aware task design, and building systems that actually work for neurodivergent minds.

curiositech/windags-skills

Designs digital experiences for ADHD brains using neuroscience research and UX principles. Expert in reducing cognitive load, time blindness solutions, dopamine-driven engagement, and compassionate design patterns. Activate on 'ADHD design', 'cognitive load', 'accessibility', 'neurodivergent UX', 'time blindness', 'dopamine-driven', 'executive function'. NOT for general accessibility (WCAG only), neurotypical UX design, or simple UI styling without ADHD context.

curiositech/windags-skills

>- Apply crisis decision-making research to agent routing, uncertainty triage, and coordination failure analysis in time-pressured systems. Use when diagnosing handoff failures, analytical paralysis, or expert judgment under incomplete information. NOT for routine coding, simple CRUD design, or static single-agent tasks with complete information.

curiositech/windags-skills

Extend and modify the admin dashboard, developer portal, and operations console. Use when adding new admin tabs, metrics, monitoring features, or internal tools. Activates for dashboard development, analytics, user management, and internal tooling.

curiositech/windags-skills

Conversation patterns and interaction protocols for multi-agent systems. Covers request/response, pub/sub, blackboard, delegation chains, debate, critique, consensus, fan-out/fan-in, supervisor-worker, and peer negotiation. Deep analysis of AutoGen conversation patterns, CrewAI delegation, LangGraph state passing, and FIPA-ACL performatives. Teaches how to design what agents say to each other and in what order. Activate on: "agent conversation", "agent protocol", "multi-agent debate", "agent delegation", "supervisor worker pattern", "agent voting", "consensus protocol", "fan-out fan-in", "agent negotiation", "blackboard pattern", "agent dialogue", "conversation topology", "agent handoff". NOT for: wire format or serialization (use agent-interchange-formats), orchestration infrastructure (use agentic-infrastructure-2026), single agent behavior (use agentic-patterns).

curiositech/windags-skills

Meta-agent for creating new custom agents, skills, and MCP integrations. Expert in agent design, MCP development, skill architecture, and rapid prototyping. Activate on 'create agent', 'new skill', 'MCP server', 'custom tool', 'agent design'. NOT for using existing agents (invoke them directly), general coding (use language-specific skills), or infrastructure setup (use deployment-engineer).

curiositech/windags-skills

AI-powered calendar management and agent-based scheduling coordination. Covers calendar APIs (Google Calendar, CalDAV/iCal), AI scheduling assistants (Reclaim, Clockwise, Motion, Cal.com), building custom calendar agents with MCP, multi-calendar merging, timezone management, focus block protection, meeting fatigue detection, and agent-to-agent meeting negotiation protocols. Activate on: "calendar agent", "AI scheduling", "calendar coordination", "meeting scheduling", "calendar API", "focus time protection", "calendar optimization", "Google Calendar MCP", "Reclaim", "Clockwise", "Motion", "Cal.com", "smart scheduling", "calendar-aware agent", "timezone scheduling", "agent negotiation meetings". NOT for: manual calendar UI component design (use form-validation-architect), project management scheduling or Gantt charts (use project-management-guru-adhd), general time-tracking or pomodoro apps (use adhd-daily-planner for time-awareness), building the agent itself from scratch (use agent-creator).

curiositech/windags-skills

Build and adopt production AI agent infrastructure in 2026. Covers framework selection (LangGraph, CrewAI, AutoGen, MCP), orchestration patterns, evaluation, observability, memory systems, and tool use. Also covers the SOCIAL dimension: how to sell agent infrastructure internally, change management, measuring ROI, building trust in autonomous systems, and scaling adoption across teams. Activate on: "agent infrastructure", "agent framework comparison", "which agent framework", "sell AI tools internally", "agent adoption", "agent observability", "agent evaluation", "MCP architecture", "agentic mesh", "enterprise AI agents", "AI change management", "agent ROI". NOT for: building specific agents (use ai-engineer), designing agent behavior patterns (use agentic-patterns), prompt tuning (use prompt-engineer).

curiositech/windags-skills

Fundamental patterns for effective agentic behavior. Teaches decomposition, tool orchestration, error recovery, context management, quality self-assessment, and knowing when to stop. Model-agnostic principles that make any agent more effective regardless of domain. Activate on: "how should I structure this agent", "agentic workflow", "agent patterns", "multi-step task", "tool orchestration", "/agentic-patterns", "decompose this", "agent best practices", "chain of actions", "when should the agent stop", "agent loop design". NOT for: creating agent infrastructure (use agent-creator), building DAGs (use windags-architect), specific tool implementation.

curiositech/windags-skills

Automated discovery and matching of agent skills for dynamic task routing and capability assessment

curiositech/windags-skills

Cryptographic security for agentic systems — zero-trust agent networking, signed message envelopes (JWS/JWE), capability-based security (ocaps), Merkle tree audit trails, WASM sandboxing, and formal verification. Covers CLI dev tool security, mTLS between agents, permission boundaries (least privilege for AI agents), and supply chain security for skills/plugins. Activate on: "agent security", "zero trust agents", "secure agent communication", "capability-based security", "ocap", "signed messages between agents", "agent audit trail", "sandbox agent execution", "agent permissions", "mTLS agents", "cryptographic verification", "agent supply chain", "OWASP agentic", "prove agent did X", "tamper-proof agent logs". NOT for: application-level SAST scanning (use security-auditor), network firewall rules (use infrastructure), SOC2/HIPAA compliance (organizational), or prompt injection defense (use prompt-engineer).

curiositech/windags-skills

Data structures and serialization formats for agent-to-agent communication. Covers message envelopes, structured output schemas, capability declarations, task handoff payloads, error/retry signaling, and context windows as data structures. Deep comparison of A2A protocol, MCP, OpenAI function calling, and LangChain message types. Teaches when to use rigid schemas vs free-form with validation, typed vs untyped, streaming vs batch. Activate on: "agent message format", "agent communication schema", "agent-to-agent protocol", "A2A protocol", "MCP message format", "structured output for agents", "agent interop", "interchange format", "agent serialization", "task handoff format", "capability declaration". NOT for: what agents say to each other (use agent-conversation-protocols), orchestration topology (use multi-agent-coordination), building agent infrastructure (use agentic-infrastructure-2026).

curiositech/windags-skills

Logic-based agent programming language implementing BDI architecture for practical autonomous agent development

curiositech/windags-skills

>- Design AgentSpeak(L)-style BDI agents with context-guarded plans, selection functions, and intention stacks. Use for interruptible autonomy, agent policy, and multi-agent orchestration in dynamic environments. NOT for simple rule engines, static planners, or centralized workflows.

curiositech/windags-skills

Foundational concurrent computation model where actors communicate exclusively through asynchronous message passing

curiositech/windags-skills

license: Apache-2.0 NOT for unrelated tasks outside this domain.

相關技能