From 316807581cfcde048b0388e84ba68709529f0663 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Mon, 30 Mar 2026 20:42:03 -0500 Subject: [PATCH] fix: parse VALKEY_URL into RedisOptions object for BullMQ connection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BullMQ v5 RedisConnection constructor does: Object.assign({ port: 6379, host: '127.0.0.1' }, opts) When opts is a URL string (via 'as unknown as ConnectionOptions'), Object.assign only copies character-index properties from the string, so the default port 6379 was never overridden — causing ECONNREFUSED against the wrong port instead of the configured 6380. Fix: parse VALKEY_URL with new URL() and return a plain RedisOptions object { host, port, ... } so Object.assign merges it correctly. --- apps/gateway/src/queue/queue.service.ts | 36 +++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/apps/gateway/src/queue/queue.service.ts b/apps/gateway/src/queue/queue.service.ts index 7dca931..a807a75 100644 --- a/apps/gateway/src/queue/queue.service.ts +++ b/apps/gateway/src/queue/queue.service.ts @@ -51,16 +51,42 @@ export interface QueueHealthStatus { // Constants // --------------------------------------------------------------------------- -export const QUEUE_SUMMARIZATION = 'mosaic:summarization'; -export const QUEUE_GC = 'mosaic:gc'; -export const QUEUE_TIER_MANAGEMENT = 'mosaic:tier-management'; +export const QUEUE_SUMMARIZATION = 'mosaic-summarization'; +export const QUEUE_GC = 'mosaic-gc'; +export const QUEUE_TIER_MANAGEMENT = 'mosaic-tier-management'; const DEFAULT_VALKEY_URL = 'redis://localhost:6380'; +/** + * Parse a Redis URL string into a BullMQ-compatible ConnectionOptions object. + * + * BullMQ v5 does `Object.assign({ port: 6379, host: '127.0.0.1' }, opts)` in + * its RedisConnection constructor. If opts is a URL string, Object.assign only + * copies character-index properties and the defaults survive — so 6379 wins. + * We must parse the URL ourselves and return a plain RedisOptions object. + */ function getConnection(): ConnectionOptions { const url = process.env['VALKEY_URL'] ?? DEFAULT_VALKEY_URL; - // BullMQ ConnectionOptions accepts a URL string (ioredis-compatible) - return url as unknown as ConnectionOptions; + try { + const parsed = new URL(url); + const opts: ConnectionOptions = { + host: parsed.hostname || '127.0.0.1', + port: parsed.port ? parseInt(parsed.port, 10) : 6380, + }; + if (parsed.password) { + (opts as Record)['password'] = decodeURIComponent(parsed.password); + } + if (parsed.pathname && parsed.pathname.length > 1) { + const db = parseInt(parsed.pathname.slice(1), 10); + if (!isNaN(db)) { + (opts as Record)['db'] = db; + } + } + return opts; + } catch { + // Fallback: hope the value is already a host string ioredis understands + return { host: '127.0.0.1', port: 6380 } as ConnectionOptions; + } } // ---------------------------------------------------------------------------