Redis Sentinel Integration#
Langfuse supports Redis Sentinel for high-availability self-hosted deployments. The sentinel path is activated via REDIS_SENTINEL_ENABLED=true and is mutually exclusive with cluster mode (REDIS_CLUSTER_ENABLED) . All sentinel-specific logic lives in createRedisSentinelInstance in packages/shared/src/server/redis/redis.ts.
Configuration#
| Environment Variable | Purpose |
|---|---|
REDIS_SENTINEL_ENABLED | Set to "true" to activate sentinel mode |
REDIS_SENTINEL_NODES | Comma-separated host:port list of sentinel endpoints |
REDIS_SENTINEL_MASTER_NAME | The monitored master name (required) |
REDIS_AUTH | Password for the Redis data node |
REDIS_USERNAME | Username for the data node (optional) |
REDIS_SENTINEL_PASSWORD | Password for the sentinel nodes (separate from data-node auth) |
REDIS_SENTINEL_USERNAME | Username for sentinel nodes |
REDIS_AUTHvsREDIS_PASSWORD: Langfuse usesREDIS_AUTH(notREDIS_PASSWORD) for the data-node password throughout the codebase . UsingREDIS_PASSWORDdirectly will have no effect; it must be mapped toREDIS_AUTH. If using Kubernetes env-var interpolation (e.g.,REDIS_AUTH=$(REDIS_PASSWORD)), confirm the expansion resolves correctly before relying on it.
Sentinel nodes can also be configured with TLS; the shared buildTlsOptions() helper applies when REDIS_TLS_ENABLED=true .
Critical Bug: Missing sentinelRetryStrategy (v3.167.4+)#
Affected versions: Confirmed on 3.167.4 and 3.214.0; both open fix PRs target unmerged code as of 2026-07-20.
Symptom#
After any Redis data-node restart or sentinel failover, all langfuse-worker queue workers (DataRetentionProcessingQueue, EvalExecutionQueue, entity-change-queue, etc.) flood logs with:
All sentinels are unreachable. Retrying from scratch after 10ms.
Errors then stop — the connections are silently broken. No new jobs are processed until the worker pod is manually restarted.
Root Cause#
createRedisSentinelInstance does not set sentinelRetryStrategy. ioredis's default sentinel retry exhausts after a bounded number of attempts and permanently abandons the connection. The existing retryStrategy and reconnectOnError in redisQueueRetryOptions only govern data-node command-level reconnects — they do not cover sentinel-address resolution.
The absence of sentinelRetryStrategy also creates a feedback loop: the 10ms default inner retry fires an error event on each failed sentinel sweep, which triggers the outer retryStrategy timer and spawns another concurrent connect() call — each one resetting retryAttempts to 0 and spawning further calls. This pile-up of concurrent connections exhausts file descriptors or causes ioredis internal inconsistency, leaving all connections permanently broken.
Fix (pending merge)#
Two community PRs address this with identical one-line changes to createRedisSentinelInstance:
- PR #13925 — adds
sentinelRetryStrategybefore...additionalOptions - PR #13931 — same fix, adds indefinite retry with backoff
The proposed strategy:
sentinelRetryStrategy: (retries: number) => Math.min(retries * 200, 10_000),
This backs off linearly up to 10 s between sentinel sweep rounds but never gives up, allowing the worker to self-heal once sentinel failover completes (typically 5–15 s). The 200 ms minimum also slows error emission enough to break the concurrent-connect feedback loop.
The fix should be placed before ...additionalOptions so callers can still override it if needed.
Workaround (until fix is merged)#
Manually restart the langfuse-worker pod after any Redis failover. If running on Kubernetes, a liveness probe that detects queue silence can automate this.
Key Source Files#
| File | Purpose |
|---|---|
packages/shared/src/server/redis/redis.ts | Sentinel instance creation (createRedisSentinelInstance), retry options, all Redis factory functions |
packages/shared/src/env.ts | Zod schema for all Redis env vars including sentinel-specific ones |
Tracking issue: #13880 — Redis Sentinel connections permanently broken after data node failover