Skip to content

Commit fdec5a0

Browse files
0skiTrigger.dev RepoOps
authored andcommitted
fix(webapp): move SSO revalidation throttle to cache Redis and fail open on slow SET
Mono-RevId: 97abba33b1d2895851eca6d9225c05fb8a99e027
1 parent 73d611b commit fdec5a0

1 file changed

Lines changed: 31 additions & 13 deletions

File tree

apps/webapp/app/services/ssoSessionRevalidation.server.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@ import type { AuthUser } from "./authUser";
88
import { logger } from "./logger.server";
99
import { ssoController } from "./sso.server";
1010

11-
// Dedicated Redis client for the single-flight throttle. Reuses the
12-
// shared REDIS_* connection (same wiring the other simple shared-state
13-
// services use).
11+
// Dedicated Redis client for the single-flight throttle. Uses the shared
12+
// cache connection (CACHE_REDIS_*), the same instance the other
13+
// request-path caches and rate limiters use.
1414
const redis = singleton("ssoRevalidationRedis", () =>
1515
createRedisClient("trigger:ssoRevalidation", {
16-
host: env.REDIS_HOST,
17-
port: env.REDIS_PORT,
18-
username: env.REDIS_USERNAME,
19-
password: env.REDIS_PASSWORD,
20-
tlsDisabled: env.REDIS_TLS_DISABLED === "true",
16+
host: env.CACHE_REDIS_HOST,
17+
port: env.CACHE_REDIS_PORT,
18+
username: env.CACHE_REDIS_USERNAME,
19+
password: env.CACHE_REDIS_PASSWORD,
20+
tlsDisabled: env.CACHE_REDIS_TLS_DISABLED === "true",
21+
clusterMode: env.CACHE_REDIS_CLUSTER_MODE_ENABLED === "1",
2122
})
2223
);
2324

@@ -62,11 +63,28 @@ export async function revalidateSsoSession(
6263

6364
// Single-flight: acquire the window. Only the request that sets the
6465
// key (NX) proceeds to the actual check; everyone else this window
65-
// treats the session as valid.
66-
const [setError, acquired] = await tryCatch(redis.set(key, "1", "EX", interval, "NX"));
67-
if (setError) {
68-
// Redis unavailable → fail-open, don't block the request.
69-
logger.warn("SSO revalidation: redis SET NX failed; skipping", { error: setError });
66+
// treats the session as valid. The SET is time-bounded so a slow Redis
67+
// round-trip fails open instead of blocking the request on the hot path.
68+
let setTimer: ReturnType<typeof setTimeout> | undefined;
69+
const [setError, acquired] = await tryCatch(
70+
Promise.race([
71+
redis.set(key, "1", "EX", interval, "NX"),
72+
new Promise<typeof REVALIDATION_TIMEOUT>((resolve) => {
73+
setTimer = setTimeout(
74+
() => resolve(REVALIDATION_TIMEOUT),
75+
env.SSO_SESSION_REVALIDATION_TIMEOUT_MS
76+
);
77+
}),
78+
])
79+
);
80+
if (setTimer) clearTimeout(setTimer);
81+
if (setError || acquired === REVALIDATION_TIMEOUT) {
82+
// Redis slow or unavailable → fail open, don't block the request. The key
83+
// (if the timed-out SET still lands) just expires on its own.
84+
logger.error("SSO revalidation: throttle SET slow/failed; skipping", {
85+
error: setError,
86+
timedOut: acquired === REVALIDATION_TIMEOUT,
87+
});
7088
return;
7189
}
7290
if (acquired !== "OK") return;

0 commit comments

Comments
 (0)