Skip to content

@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

ts
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):

ts
import { ProcessMediaQueue } from "@playpals/queue";

await ProcessMediaQueue.add("media-processing", { mediaId: media.id });

Consuming (apps/ogun/src/index.ts):

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

SettingValueMeaning
attempts3Total tries per job
backoff.typeexponential2 s, 4 s, 8 s
backoff.delay2000Base 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

VariableDefaultNotes
REDIS_HOSTlocalhost
REDIS_PORT6379
REDIS_PASSWORDThe local Compose Redis uses playpalz
REDIS_URLPresent in .env.example; the queue itself uses host/port/password

Adding a queue

  1. Export a new name constant and Queue instance from packages/queue/src/index.ts.
  2. Add a Worker for it — in ogun if it is media-shaped, otherwise in a new service.
  3. 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.

Internal documentation — PlayPalz platform