feat: add REDIS_KEY_PREFIX env var for Redis ACL namespace isolation (#365)

* feat: add REDIS_KEY_PREFIX env var for Redis ACL namespace isolation

Adds optional REDIS_KEY_PREFIX env var that prefixes all Redis keys
(BullMQ queues via `prefix` option, cache/lock/rate-limit keys via
`redisKey()` helper). When unset, behavior is unchanged (BullMQ
defaults to "bull:", cache keys are unprefixed).

This enables self-hosters using Redis ACL multi-tenancy to restrict
useSend to its own key namespace (e.g. `~usesend:*`).

16 files changed across env schema, Redis module, 9 BullMQ queue/worker
files, and 5 direct Redis key operation sites.

* docs: add REDIS_KEY_PREFIX to self-host assets and fix docker run example

Add REDIS_KEY_PREFIX env var to docker/prod/compose.yml, .env.example,
.env.selfhost.example, and self-hosting docs. Fix missing trailing
backslashes in standalone docker run example.

* fix(redis): disable ioredis ready check and BullMQ version check

Redis ACL blocks INFO command (in @dangerous category). ioredis uses
INFO for ready check, BullMQ uses it for version detection. Without
these flags, BullMQ workers fail to initialize and silently stop
processing jobs.

- Add enableReadyCheck: false to ioredis connection
- Add skipVersionCheck: true to all 5 Queue + 5 Worker constructors

* fix(redis): add skipVersionCheck to remaining BullMQ job queues

Add skipVersionCheck: true to Queue and Worker constructors in all 4 job
files (campaign-scheduler, cleanup-email-bodies, usage-job,
webhook-cleanup) to match the pattern already used in service files.
This prevents BullMQ version mismatch errors when using REDIS_KEY_PREFIX
with Redis ACL namespace isolation.
This commit is contained in:
Michał Ordon
2026-03-01 21:12:47 +00:00
committed by GitHub
parent 69eeb2d96e
commit 62d7c44efc
21 changed files with 100 additions and 37 deletions
@@ -5,7 +5,7 @@ import { convert as htmlToText } from "html-to-text";
import { getConfigurationSetName } from "~/utils/ses-utils";
import { db } from "../db";
import { sendRawEmail } from "../aws/ses";
import { getRedis } from "../redis";
import { getRedis, BULL_PREFIX } from "../redis";
import { DEFAULT_QUEUE_OPTIONS } from "../queue/queue-constants";
import { logger } from "../logger/log";
import { createWorkerHandler, TeamJob } from "../queue/bullmq-context";
@@ -25,12 +25,14 @@ function createQueueAndWorker(region: string, quota: number, suffix: string) {
const queueName = `${region}-${suffix}`;
const queue = new Queue(queueName, { connection });
const queue = new Queue(queueName, { connection, prefix: BULL_PREFIX, skipVersionCheck: true });
// TODO: Add team context to job data when queueing
const worker = new Worker(queueName, createWorkerHandler(executeEmail), {
concurrency: quota,
connection,
prefix: BULL_PREFIX,
skipVersionCheck: true,
});
return { queue, worker };