diff --git a/.changeset/two-facts-think.md b/.changeset/two-facts-think.md new file mode 100644 index 0000000..b280978 --- /dev/null +++ b/.changeset/two-facts-think.md @@ -0,0 +1,5 @@ +--- +"@workflow-worlds/redis": patch +--- + +fix(redis): added constructor options to connect to Redis with TLS for the main and BullMQ clients diff --git a/packages/redis/README.md b/packages/redis/README.md index c05aa44..1b8883e 100644 --- a/packages/redis/README.md +++ b/packages/redis/README.md @@ -48,8 +48,15 @@ interface RedisWorldConfig { // Redis connection string // Default: process.env.WORKFLOW_REDIS_URI ?? 'redis://localhost:6379' redisUrl?: string; - - // Pre-existing ioredis client (if provided, redisUrl is ignored) + + // TLS options for Redis connection + tls?: { + key?: string | Buffer | (string | Buffer | KeyObject)[]; + cert?: string | Buffer | (string | Buffer)[]; + ca?: string | Buffer | (string | Buffer)[]; + }; + + // Pre-existing ioredis client (if provided, redisUrl and tls are ignored) client?: Redis; // Key prefix for all Redis keys diff --git a/packages/redis/src/index.ts b/packages/redis/src/index.ts index dd844ec..7863479 100644 --- a/packages/redis/src/index.ts +++ b/packages/redis/src/index.ts @@ -24,6 +24,7 @@ import type { WorkflowRun, WorkflowRunWithoutData, } from '@workflow/world'; +import type { ConnectionOptions } from 'tls'; import { Redis } from 'ioredis'; import type { Redis as RedisClient } from 'ioredis'; import { createQueue, type QueueConfig } from './queue.js'; @@ -34,7 +35,7 @@ import { debug } from './utils.js'; // Module-level client cache to share connections across multiple createWorld() calls const clientCache = new Map(); -function getOrCreateClient(redisUrl: string): RedisClient { +function getOrCreateClient(redisUrl: string, tls?: ConnectionOptions): RedisClient { const existing = clientCache.get(redisUrl); if (existing) { return existing; @@ -42,6 +43,7 @@ function getOrCreateClient(redisUrl: string): RedisClient { const client = new Redis(redisUrl, { maxRetriesPerRequest: null, // Required for BullMQ enableReadyCheck: false, // Faster connection + tls, }); clientCache.set(redisUrl, client); @@ -70,6 +72,11 @@ export interface RedisWorldConfig extends QueueConfig, StreamerConfig, RedisStor */ redisUrl?: string; + /** + * TLS options for the Redis connection. + */ + tls?: ConnectionOptions; + /** * Pre-existing ioredis client to use. * If provided, redisUrl is ignored. @@ -91,7 +98,7 @@ export function createWorld(config: RedisWorldConfig = {}): World { ?? 'redis://localhost:6379'; // Use provided client or create/get cached one - const client = config.client ?? getOrCreateClient(redisUrl); + const client = config.client ?? getOrCreateClient(redisUrl, config.tls); debug('Creating world with:', { redisUrl: redisUrl.replace(/\/\/[^:]*:[^@]*@/, '//***:***@'), // Hide credentials diff --git a/packages/redis/src/queue.ts b/packages/redis/src/queue.ts index 50068c5..d628d37 100644 --- a/packages/redis/src/queue.ts +++ b/packages/redis/src/queue.ts @@ -10,6 +10,7 @@ */ import { Queue, Worker, Job, type ConnectionOptions, type JobsOptions } from 'bullmq'; +import type { ConnectionOptions as TlsConnectionOptions } from 'tls'; import type { Queue as WorkflowQueue, MessageId, @@ -31,6 +32,11 @@ export interface QueueConfig { */ baseUrl?: string; + /** + * TLS options for the Redis connection. + */ + tls?: TlsConnectionOptions; + /** * Maximum concurrent message processing. * Default: 20 @@ -88,6 +94,11 @@ export async function createQueue(options: { const connection: ConnectionOptions = { url: redisUrl, maxRetriesPerRequest: null, + tls: config.tls ? { + key: config.tls.key, + cert: config.tls.cert, + ca: config.tls.ca, + } : undefined, }; // Create BullMQ queues for workflow and step execution