feat: add Redis Cluster mode support (GCP Memorystore, AWS ElastiCache)#17
Open
pedrojreis wants to merge 3 commits into
Open
feat: add Redis Cluster mode support (GCP Memorystore, AWS ElastiCache)#17pedrojreis wants to merge 3 commits into
pedrojreis wants to merge 3 commits into
Conversation
… handling * Refactor job processing in workers.ts for improved readability and maintainability. * Introduce Redis connection management in redis-connection.ts. * Add tests for Redis connection utilities in redis-connection.test.ts. * Implement TLS options handling for secure Redis connections. * Enhance error handling and logging throughout the job processing flow.
* Updated the project dependency to version 2.3.1. * Ensured compatibility with existing codebase. * Ran tests to verify functionality post-upgrade.
0aabfff to
418e509
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Adds opt-in Redis Cluster support to every service component. Standalone
Redis remains the default — existing deployments require zero configuration
changes and behave exactly as before.
Validated in production against Google Cloud Memorystore in cluster mode with
TLS and CA-certificate verification.
Motivation
The service previously constructed Redis connections with inline
new IORedis({ ... })calls in four separate modules, each hardcoded tostandalone mode. Connecting to a clustered Redis (GCP Memorystore cluster, AWS
ElastiCache cluster) was impossible: the client would only ever reach a single
shard and fail with
MOVED/CROSSSLOTerrors under load.This PR centralizes connection creation behind a single factory and teaches
every component to speak the Redis Cluster protocol when asked.
What's new
🔌 Cluster mode (opt-in, auto-detected)
Enable it either explicitly or implicitly:
🔐 TLS with CA-certificate validation
When
REDIS_CAis set it takes precedence and enables validated TLS.REDIS_TLS=trueon its own keeps the previousrejectUnauthorized: falsebehaviour for backward compatibility.
🧩 BullMQ cluster-safety
Queue, Worker and QueueEvents receive a
{codeapi}hash-tag prefix in clustermode so all BullMQ keys map to a single hash slot (a hard requirement for BullMQ
on Redis Cluster). Standalone deployments keep their existing key layout — no
migration needed.
New environment variables
USE_REDIS_CLUSTERfalseREDIS_HOSTcontains a comma.REDIS_CAREDIS_TLS.Existing variables are unchanged and fully backward-compatible:
REDIS_HOST,REDIS_PORT,REDIS_PASSWORD,REDIS_TLS,REDIS_USE_ALTERNATIVE_DNS_LOOKUP,REDIS_KEEP_ALIVE_MS.Implementation
service/src/redis-connection.ts(new — single source of truth)createRedisConnection(overrides)Redis | Clusterbased on env; each caller passes its own retry / readyCheck overridesisClusterMode()USE_REDIS_CLUSTER=trueor comma inREDIS_HOSTparseRedisNodes()REDIS_HOSTinto[{ host, port }]startup nodesbuildTlsOptions()REDIS_CA→{ ca }(validated); elseREDIS_TLS=true→{ rejectUnauthorized: false }; else no TLSbullmqPrefix()'{codeapi}'in cluster mode,undefinedotherwiseRefactored clients
All four inline
new IORedis({ ... })blocks now callcreateRedisConnection():queue.ts— shared BullMQ connection +prefix: bullmqPrefix()onQueue/QueueEventsworkers.ts—prefix: bullmqPrefix()on bothWorkerinstancesegress-ledger.ts— mutation-connection pool made cluster-safe (Clusterhas no.duplicate(), so a freshcreateRedisConnection()is used instead)tool-call-server.ts,file-server.ts— session-state clientsservice/src/service/replay-state.tsscanKeys()is now cluster-aware.ioredis.Clusterhas no top-levelscanStream, so in cluster mode the helper fans out across every master nodevia
cluster.nodes('master')and streamsSCANon each. Masters own disjointhash-slot ranges, so results never overlap. This fixes the runtime crash:
service/src/config.tsAdds the
USE_REDIS_CLUSTERflag to the parsed env.Helm chart (
helm/codeapi/)New
values.yamlsurface:New
_helpers.tpltemplates —codeapi.redis.clusterEnabled,codeapi.redis.tlsEnv,codeapi.redis.caVolume,codeapi.redis.caVolumeMount— are wired into all five component Deployments, including mounting the CA cert
from a Secret into each pod.
service/.env.exampleDocuments every new variable with inline guidance.
Tests
New
service/src/redis-connection.test.ts— 18 unit tests, no live Redis required:parseRedisNodesisClusterModebuildTlsOptionsREDIS_TLSonly,REDIS_CAfile read, CA precedence overREDIS_TLS, missing CA filebullmqPrefixBackward compatibility
REDIS_TLS=truewithoutREDIS_CAkeeps the priorrejectUnauthorized: falsebehaviour.How to verify