Skip to content

fix(redis): apply TLS SNI override to pub/sub clients#4638

Merged
TheodoreSpeaks merged 3 commits into
stagingfrom
fix/redis-pubsub-sni
May 17, 2026
Merged

fix(redis): apply TLS SNI override to pub/sub clients#4638
TheodoreSpeaks merged 3 commits into
stagingfrom
fix/redis-pubsub-sni

Conversation

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator

  • fix(redis): pub/sub clients in lib/events/pubsub.ts were building their own ioredis instances directly (pub/sub needs dedicated connections), bypassing the SNI override added in feat(redis): TLS SNI override for IP-based REDIS_URL + zod schema fixes #4635. trigger.dev tasks hit 'Hostname/IP does not match certificate's altnames' on every pub/sub connect against the PrivateLink VPCE IP. Export the helper as resolveRedisTlsOptions and apply it to the pub/sub clients too.

Pub/sub clients in lib/events/pubsub.ts build their own ioredis instances
directly via new Redis(redisUrl, ...) because pub/sub needs dedicated
connections (can't multiplex on the shared client from getRedisClient).
That path skipped the resolveTlsOptions helper added for trigger.dev's
PrivateLink VPCE IP, so every pub/sub channel hit
'Hostname/IP does not match certificate's altnames' on connect.

Export the helper as resolveRedisTlsOptions and use it from pubsub.ts.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped May 17, 2026 5:23am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 17, 2026

PR Summary

Medium Risk
Changes Redis connection construction for pub/sub and centralizes shared defaults; misconfiguration of REDIS_TLS_SERVERNAME can now fail fast instead of falling back to local pub/sub, impacting multi-replica deployments.

Overview
Adds getRedisConnectionDefaults() in lib/core/config/redis.ts to centralize common ioredis options and the TLS SNI override (renaming the internal helper to resolveRedisTlsOptions).

Updates lib/events/pubsub.ts to use these shared defaults for its dedicated publish/subscribe Redis connections, and resolves defaults outside the try/catch so TLS misconfiguration (missing REDIS_TLS_SERVERNAME for rediss:// IP URLs) fails loudly rather than silently falling back to the in-process EventEmitter.

Reviewed by Cursor Bugbot for commit ba0a983. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b58fa66. Configure here.

Comment thread apps/sim/lib/events/pubsub.ts Outdated
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 17, 2026

Greptile Summary

This PR fixes a TLS SNI mismatch on trigger.dev tasks by applying the rediss://-over-IP SNI override to pub/sub Redis clients, which were previously creating their own ioredis instances without it. The helper is renamed resolveRedisTlsOptions and exported so pubsub.ts can import and use it.

  • redis.ts: Renames and exports resolveRedisTlsOptions; no logic change.
  • pubsub.ts: Calls resolveRedisTlsOptions in the RedisPubSubChannel constructor and spreads the result into commonOpts, matching how the main Redis client is already configured.

Confidence Score: 4/5

Safe to merge for the targeted PrivateLink/SNI fix; the only concern is a pre-existing fallback that would swallow a misconfiguration error rather than surfacing it.

The fix is correct and minimal: TLS options are now consistently applied to all three Redis connections (main, pub, sub). The one edge case is that if REDIS_TLS_SERVERNAME is missing while REDIS_URL targets an IP over rediss://, the error thrown by resolveRedisTlsOptions inside the constructor will be caught by createPubSubChannel's existing fallback and silently degrade pub/sub to local EventEmitter mode — unlike getRedisClient(), which deliberately surfaces the same error. In a correctly configured PrivateLink deployment this code path won't be hit, so it does not affect the fix itself.

apps/sim/lib/events/pubsub.ts — the existing error-swallowing fallback in createPubSubChannel now also masks resolveRedisTlsOptions config errors.

Important Files Changed

Filename Overview
apps/sim/lib/core/config/redis.ts Renames resolveTlsOptions to resolveRedisTlsOptions and exports it; internal call site updated. Purely mechanical, no logic change.
apps/sim/lib/events/pubsub.ts Imports resolveRedisTlsOptions and applies TLS options to pub/sub Redis clients. Correct fix for the SNI override gap, but a config error thrown by the helper will be caught by the existing createPubSubChannel fallback and silently degrade to local EventEmitter mode.

Sequence Diagram

sequenceDiagram
    participant pubsub as pubsub.ts
    participant helper as resolveRedisTlsOptions
    participant env as REDIS_TLS_SERVERNAME
    participant redis as ioredis (pub/sub)

    pubsub->>helper: resolveRedisTlsOptions(redisUrl)
    helper->>helper: parse URL, check rediss:// + IP host
    helper->>env: read REDIS_TLS_SERVERNAME
    alt REDIS_TLS_SERVERNAME set
        helper-->>pubsub: "{ servername: "elasticache-dns" }"
        pubsub->>redis: "new Redis(redisUrl, { tls: { servername } })"
        redis-->>pubsub: connected (SNI override applied)
    else REDIS_TLS_SERVERNAME missing
        helper-->>pubsub: throws Error
        Note over pubsub: caught by createPubSubChannel try-catch
        pubsub->>pubsub: fallback to LocalPubSubChannel
    end
Loading

Comments Outside Diff (1)

  1. apps/sim/lib/events/pubsub.ts, line 148-154 (link)

    P2 Config error silently swallowed by fallback

    resolveRedisTlsOptions is now called inside the RedisPubSubChannel constructor, which is itself inside a try-catch in createPubSubChannel. If REDIS_URL targets an IP over rediss:// but REDIS_TLS_SERVERNAME is not set, the function throws — but the catch block swallows it and returns a LocalPubSubChannel, giving only a log line and leaving pub/sub silently in-process-only mode. By contrast, getRedisClient() deliberately places the same call outside its try-catch with the comment "config errors aren't silently swallowed." To stay consistent, resolveRedisTlsOptions (or the full new RedisPubSubChannel) call could be hoisted outside the try-catch, so a misconfiguration crashes loudly rather than degrading to local-only pub/sub.

Reviews (1): Last reviewed commit: "fix(redis): apply TLS SNI override to pu..." | Re-trigger Greptile

Extract keepAlive/connectTimeout/enableOfflineQueue + TLS SNI into a
single getRedisConnectionDefaults helper. Main client and pub/sub
clients both spread it; caller-specific retry/timeout policy stays
per-caller (pub/sub still needs maxRetriesPerRequest: null and a
different retry strategy for SUBSCRIBE).
resolveRedisTlsOptions (via getRedisConnectionDefaults) throws if
REDIS_TLS_SERVERNAME is missing for an IP-based rediss:// URL. Calling
it inside the constructor let createPubSubChannel's try/catch swallow
the error and fall back to in-process EventEmitter — silent
cross-replica pub/sub breakage in prod. Resolve defaults before the
try so config errors propagate; only catch genuine runtime construction
failures.
@TheodoreSpeaks TheodoreSpeaks merged commit 4945d55 into staging May 17, 2026
14 checks passed
@TheodoreSpeaks TheodoreSpeaks deleted the fix/redis-pubsub-sni branch May 17, 2026 05:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant