@@ -8,16 +8,17 @@ import type { AuthUser } from "./authUser";
88import { logger } from "./logger.server" ;
99import { 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.
1414const 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