Files
mcpedia/content/docs/bullmq/workers.md
T
asepharyana 53d636af0e
CI / typecheck + build (turbo) (push) Canceled after 0s
feat(phase7): grow corpus, MCP write-tools+auth, /metrics observability
- content/: +5 real docs (caddy, bullmq, mcp-streamable-http, postgres-fts,
  cloudflare-525 writeup) across docs/writeups/notes. Reindexed: 9 docs, 17
  chunks, 5 revisions (was 4 docs).
- apps/mcp: add write-tools index_document/reindex_all/restore_revision (require
  x-webhook-secret) + queue_status (public). createMcpServer(authSecret?) threads
  the HTTP header; stdio keeps writes open (trusted local).
- apps/api: GET /metrics (Prometheus text: uptime + queue job gauges).
- Caddy: expose /metrics on wiki. domain -> :4020.
Verified live: /metrics 200; MCP tools/list -> 10; index_document unauth -> error,
auth -> enqueues + worker drains; typecheck green.
2026-08-20 10:04:16 +07:00

69 lines
2.1 KiB
Markdown

---
id: bullmq-workers
title: BullMQ Background Workers
type: documentation
tags:
- bullmq
- redis
- jobs
- queue
- infra
status: published
author: asep
created_at: 2026-08-20
updated_at: 2026-08-20
---
# BullMQ Background Workers
BullMQ runs the async indexing/embedding pipeline. Jobs are enqueued by the CLI, the
git-sync webhook, or an MCP tool, and drained by a long-running worker connected to the
shared Redis instance.
## Connection requirements
BullMQ requires an **ioredis** connection with `maxRetriesPerRequest: null`. A finite
retry count causes the cryptic `Connection in key mode` error on blocking commands.
The shared client in `packages/queue` sets this correctly:
```ts
const opts: RedisOptions = {
maxRetriesPerRequest: null,
lazyConnect: true,
enableOfflineQueue: true,
};
```
## Job model
Three job types flow through the `mcpedia-index` queue (prefix `mcpedia:` on Redis):
| name | data | action |
|------------|-------------------|---------------------------------|
| `index-doc`| `{ relPath, reason }` | index one content file |
| `index-all`| `{ reason }` | full corpus reindex |
| `reindex` | (legacy) | alias of full |
Job IDs use a `__` separator (`doc__<slug>`, `full__<ts>`) — BullMQ reserves `:` for
repeatable jobs, so a literal `:` in a custom jobId is rejected.
## Worker lifecycle
The worker is a `Worker` with `concurrency: 4`. Each job calls the shared
`indexContentFile` / `runFullIndex` entry points in `@mcpedia/core` — the same code
path the CLI uses, so behavior never diverges. On completion it logs; on failure it
logs the reason and the job is retried per BullMQ defaults.
Graceful shutdown: `worker.close()` on `SIGINT`/`SIGTERM`. systemd sends SIGTERM on
stop, so the process exits cleanly and in-flight jobs are returned to the queue.
## Inspecting state
```bash
bun run enqueue --all # enqueue a full reindex
curl localhost:4020/trpc/queueStatus # waiting/active/completed/failed
```
A stuck queue (waiting > 0, active = 0) means the worker died — check
`systemctl status mcpedia-worker` and the journal.