Midday / apps /worker /src /config.ts
Jules
Final deployment with all fixes and verified content
c09f67c
import { createLoggerWithContext } from "@midday/logger";
const logger = createLoggerWithContext("worker:config");
const isProduction =
process.env.NODE_ENV === "production" ||
process.env.RAILWAY_ENVIRONMENT === "production";
/**
* Parse Redis URL and return connection options for BullMQ
* BullMQ will create and manage its own Redis connections
*/
function parseRedisUrl() {
const redisUrl = process.env.REDIS_QUEUE_URL;
if (!redisUrl) {
throw new Error("REDIS_QUEUE_URL environment variable is required");
}
const url = new URL(redisUrl);
return {
host: url.hostname,
port: Number(url.port) || 6379,
password: url.password || undefined,
username: url.username || undefined,
// TLS for production (rediss://)
...(url.protocol === "rediss:" && {
tls: {},
}),
};
}
/**
* Get Redis connection options for BullMQ queues and workers
* BullMQ will create its own connection with these options
*
* Based on BullMQ recommended settings:
* - maxRetriesPerRequest: null (required for Workers)
* - retryStrategy: exponential backoff (min 1s, max 20s)
* - enableOfflineQueue: true (Workers need to wait for reconnection)
* - reconnectOnError: auto-reconnect on READONLY (cluster failover)
*
* @see https://docs.bullmq.io/guide/going-to-production
*/
export function getRedisConnection() {
const baseOptions = parseRedisUrl();
return {
...baseOptions,
// BullMQ required settings for Workers
maxRetriesPerRequest: null, // Required: retry indefinitely for Workers
enableReadyCheck: false,
// Network settings
lazyConnect: false,
family: 4,
keepAlive: 30000, // TCP keep-alive every 30s
connectTimeout: isProduction ? 15000 : 5000,
// BullMQ recommended retry strategy: exponential backoff
// 1s, 2s, 4s, 8s, 16s, then capped at 20s
retryStrategy: (times: number) => {
const delay = Math.min(1000 * 2 ** times, 20000);
if (times > 5) {
logger.info(
`[Redis/Worker] Reconnecting in ${delay}ms (attempt ${times})`,
);
}
return delay;
},
// Auto-reconnect on errors that indicate failover/upgrade
// READONLY: Redis is in replica mode during failover/upgrade
// ETIMEDOUT/timed out: Connection or script timed out (can happen during failover)
reconnectOnError: (err: Error) => {
const msg = err.message;
if (msg.includes("READONLY")) {
logger.info(
"[Redis/Worker] READONLY error detected (server upgrade/failover), reconnecting",
);
return true;
}
if (msg.includes("timed out") || msg.includes("ETIMEDOUT")) {
logger.info("[Redis/Worker] Timeout error detected, reconnecting");
return true;
}
return false;
},
};
}
/**
* Get Redis connection options for FlowProducer
* BullMQ best practice: separate connections for Queue, Worker, and FlowProducer
*/
export function getFlowRedisConnection() {
// Same options - BullMQ will create a separate connection
return getRedisConnection();
}