Node.js Redis接続シングルトンパターン + 自動再接続戦略
問題
複数のモジュールがそれぞれcreateClient()を呼び出すと、Redis接続が重複して作成されます。さらに、ネットワーク切断時に再接続ロジックがないと、アプリがそのまま停止してしまいます。
解決方法
import { createClient, RedisClientType } from 'redis';
let redisClient: RedisClientType | null = null;
let isConnecting = false;
export async function getRedisClient(): Promise<RedisClientType> {
// すでに接続されていればそのまま返す
if (redisClient && redisClient.isOpen) {
return redisClient;
}
// 他の箇所で接続中なら待機
if (isConnecting) {
while (isConnecting) {
await new Promise(resolve => setTimeout(resolve, 100));
}
if (redisClient && redisClient.isOpen) return redisClient;
}
isConnecting = true;
try {
redisClient = createClient({
url: process.env.REDIS_URL || 'redis://127.0.0.1:6379',
socket: {
reconnectStrategy: (retries) => {
if (retries > 10) return new Error('Max retries reached');
return Math.min(retries * 100, 3000); // 指数バックオフ
}
}
});
await redisClient.connect();
return redisClient;
} finally {
isConnecting = false;
}
}
ポイント
isConnectingフラグにより、複数箇所から同時にconnect()が呼ばれるのを防ぎます。これがないと、サーバー起動時の同時リクエストで接続が重複して作成されます。reconnectStrategyではretries * 100で100ms、200ms、300ms…と増加し、Math.minで最大3秒まで待機します。10回失敗したら諦めます。finallyブロックでisConnecting = falseにするのが重要です。接続失敗時にもフラグが解除されないと、次の試行ができなくなります。