diff --git a/src/app.ts b/src/app.ts index 1cfb85f..6f1cac5 100644 --- a/src/app.ts +++ b/src/app.ts @@ -32,14 +32,31 @@ app.use(cookieParser()); if (getEnv() === Env.prod) { const redisClient = createClient({ url: config.get('redis.url'), + // Periodically PING so a half-open connection (e.g. after the Redis + // server restarts behind a stable ClusterIP) is detected and a + // reconnect is triggered. Without this, node-redis keeps queueing + // commands on the dead socket and express-session never gets a reply, + // so every session-writing request (e.g. /auth-oidc) hangs forever + // until the pod is restarted. + pingInterval: 10000, + socket: { + keepAlive: 5000, + connectTimeout: 10000, + // Keep retrying with capped backoff instead of giving up. + reconnectStrategy: (retries) => Math.min(retries * 100, 3000), + }, }); + // node-redis throws (and can crash the process) if an 'error' is emitted + // with no listener; log it and let the reconnect strategy recover. + redisClient.on('error', (err) => logger.error(`Redis session store error: ${err}`)); + sessionStore = new RedisStore({ prefix: 'walias:', client: redisClient, }); - redisClient.connect().catch(console.error); + redisClient.connect().catch((err) => logger.error(`Redis initial connect failed: ${err}`)); } app.use(