Add timeouts and bounded reconnect to Redis client#120
Conversation
Previously the Redis client retried reconnecting forever with no connect or command timeout, so an unreachable Redis made callers (e.g. the OAuth token exchange) block indefinitely instead of failing. Bound the reconnect attempts, set a connect timeout, and cap each command so Redis outages surface as errors. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3397557. Configure here.
| } finally { | ||
| if (timer) clearTimeout(timer); | ||
| } | ||
| } |
There was a problem hiding this comment.
Timeout leaves unhandled rejection
Medium Severity
The withTimeout function uses Promise.race but doesn't manage the underlying Redis operation when the timeout wins. This can lead to unhandled promise rejections and unintended Redis mutations if the original operation completes later.
Reviewed by Cursor Bugbot for commit 3397557. Configure here.
| async function withReconnect<T>(operation: () => Promise<T>): Promise<T> { | ||
| try { | ||
| return await operation(); | ||
| return await withTimeout(operation); |
There was a problem hiding this comment.
Connect await exceeds command timeout
High Severity
The new withTimeout wrapper only covers the Redis command inside withReconnect, while every exported helper still awaits ensureConnected() first. On a cold instance with Redis down, that connect/reconnect loop can run many connectTimeout cycles plus backoff before reconnectStrategy gives up, so OAuth paths like /token can keep blocking far beyond the 5s command ceiling this PR adds.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 3397557. Configure here.
| ); | ||
| } | ||
| return Math.min(500 + retries * 100, 2000); | ||
| }; |
There was a problem hiding this comment.
Reconnect limit off by one
Low Severity
reconnectStrategy stops only when retries > MAX_RECONNECT_ATTEMPTS (10), so node-redis can still schedule backoff for retries 0 through 10 before returning an error. That is one more delayed reconnect cycle than MAX_RECONNECT_ATTEMPTS and the error text imply.
Reviewed by Cursor Bugbot for commit 3397557. Configure here.


Summary
The Redis client retried reconnecting forever with no connect or command timeout. When Redis was unreachable, any command (e.g. the OAuth org-context writes in
/token) blocked until the serverless function limit instead of throwing — sokernel loginhung after the browser showed "authentication successful" rather than failing with an error.This bounds the failure:
reconnectStrategynow returns anErrorafterMAX_RECONNECT_ATTEMPTS(10) instead of retrying indefinitely, so queued commands reject when Redis stays down.connectTimeout(5s) on the socket so a black-holed connection fails fast.withTimeout(5s ceiling) so a stalled-but-connected command surfaces as an error.Net effect: a Redis outage returns a clean error in seconds instead of hanging the caller.
Test plan
tsc --noEmitpassesFollow-up companion PR on
kernel/cliadds a timeout on the CLI token exchange so it also fails fast.Note
Medium Risk
Touches shared Redis plumbing used by OAuth token/authorize flows; mis-tuned timeouts could cause false failures under slow Redis, but behavior on healthy Redis should match prior reconnect/retry semantics.
Overview
When Redis is unreachable, OAuth-related calls (e.g. org-context writes on
/token) could block until the serverless function limit instead of failing—so CLI login could hang after the browser showed success.src/lib/redis.tsnow caps failure time: 5s socketconnectTimeout,reconnectStrategystops after 10 attempts (returns anErrorinstead of retrying forever), andwithTimeoutwraps every command inwithReconnectwith a 5s ceiling. Transient socket errors still get one reconnect + retry, but both attempts are timeout-bounded.Happy path against healthy Redis is unchanged; outages should surface as errors within seconds rather than indefinite hangs.
Reviewed by Cursor Bugbot for commit 3397557. Bugbot is set up for automated code reviews on this repo. Configure here.