Production Cheatsheet

One-screen launch gate. Cite: Going to Production, Connections, Concurrency, Graceful Shutdown, Sandboxed.

Redis config (NOT in your code)

SettingValueWhy
maxmemory-policynoevictionEviction silently corrupts queues. Only safe value.
PersistenceAOF, ~1s fsyncSurvives restarts without losing pending jobs. Often off by default.
Managed Redis usually ships as a cache (LRU + no persistence). Flip both before launch.

Connection rule

const connection = new IORedis({ maxRetriesPerRequest: null });  // MANDATORY
ClassHeld
Queue1 (sharable)
Worker1 + internal duplicate (blocking)
QueueEvents1 + internal duplicate (blocking)
new Queue('email', { prefix: 'myapp-prod', connection });  // isolate envs

Graceful shutdown

let down = false;
async function shutdown() {
  if (down) return; down = true;
  await worker.close();    // no new jobs; waits for active (NO self-timeout!)
  await queue.close();
  await connection.quit();
  process.exit(0);
}
process.on('SIGTERM', shutdown).on('SIGINT', shutdown);
worker.close() never self-times-out. Race it vs your grace period, or accept long jobs stall & get re-queued elsewhere.

Scaling model

Work typeKnobNote
I/O-boundconcurrency: N (high)Exploits event-loop wait time.
CPU-boundMore worker processesScales ~linearly. High concurrency hurts.
Blocks event loopSandboxed processoruseWorkerThreads: true (v3.13+).

Idempotency — required

Retries, stalls, rate-limit re-queues, flow resumes all re-run jobs. Guard side-effects (idempotency keys, dedup flags, upserts). Non-idempotent = double charges / double sends.

🚀 Launch checklist