@playpals/queue
packages/queue
A single BullMQ queue definition, shared so the producer (api) and the consumer (ogun) cannot disagree about its name, connection, or retry policy.
The whole package
import { Queue } from "bullmq";
import { config } from "./config";
import Redis from "ioredis";
export const PROCESS_MEDIA_QUEUE = "media-processing";
const connection = new Redis(config.redis.port, config.redis.host, {
password: config.redis.password,
maxRetriesPerRequest: null,
});
connection.on("error", (err) => {
console.error("[queue] redis error", err);
});
export const ProcessMediaQueue = new Queue(PROCESS_MEDIA_QUEUE, {
connection,
defaultJobOptions: {
attempts: 3,
backoff: { type: "exponential", delay: 2000 },
},
});That is the entire surface. Its value is not the code, it is that the queue name and retry policy exist in exactly one place.
Usage
Producing (apps/api/src/controllers/media.ts):
import { ProcessMediaQueue } from "@playpals/queue";
await ProcessMediaQueue.add("media-processing", { mediaId: media.id });Consuming (apps/ogun/src/index.ts):
import { PROCESS_MEDIA_QUEUE } from "@playpals/queue";
new Worker(PROCESS_MEDIA_QUEUE, async (job) => processMedia(job.data.mediaId), {
connection: redis,
concurrency: 5,
});Note that ogun builds its own Redis connection for the worker rather than reusing this one — a worker connection has different requirements from a producer connection.
Retry policy
| Setting | Value | Meaning |
|---|---|---|
attempts | 3 | Total tries per job |
backoff.type | exponential | 2 s, 4 s, 8 s |
backoff.delay | 2000 | Base delay in ms |
After the third failure the job moves to the failed set and stays there for inspection.
maxRetriesPerRequest: null
BullMQ requires this on its ioredis connections. Without it, ioredis gives up on a command after a few retries and BullMQ's blocking operations break in ways that are hard to diagnose. Do not remove it.
Configuration
| Variable | Default | Notes |
|---|---|---|
REDIS_HOST | localhost | |
REDIS_PORT | 6379 | |
REDIS_PASSWORD | — | The local Compose Redis uses playpalz |
REDIS_URL | — | Present in .env.example; the queue itself uses host/port/password |
Adding a queue
- Export a new name constant and
Queueinstance frompackages/queue/src/index.ts. - Add a
Workerfor it — inogunif it is media-shaped, otherwise in a new service. - Rebuild the package so both sides pick up the export.
Keep the name constant in this package. A hard-coded queue string in two repositories' worth of services is exactly the bug this package exists to prevent.
