| 70 | * Fails fast if Redis is not available - consumers handle reconnection |
| 71 | */ |
| 72 | export async function getCacheService(): Promise<Result<CacheService, CacheError>> { |
| 73 | // Return existing instance immediately |
| 74 | if (singleton) { |
| 75 | const rc = singleton.getRedisClient(); |
| 76 | if (rc?.isReady && rc.isOpen) return ok(singleton); |
| 77 | } |
| 78 | |
| 79 | // Return existing instance from globalForCache if available |
| 80 | if (globalForCache.formbricksCache) { |
| 81 | const rc = globalForCache.formbricksCache.getRedisClient(); |
| 82 | if (rc?.isReady && rc.isOpen) { |
| 83 | singleton = globalForCache.formbricksCache; |
| 84 | return ok(globalForCache.formbricksCache); |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | // Prevent concurrent initialization |
| 89 | if (globalForCache.formbricksCacheInitializing) { |
| 90 | const result = await globalForCache.formbricksCacheInitializing; |
| 91 | if (result.ok) { |
| 92 | singleton = result.data; |
| 93 | } |
| 94 | return result; |
| 95 | } |
| 96 | |
| 97 | // Start initialization - fail fast approach |
| 98 | globalForCache.formbricksCacheInitializing = (async (): Promise<Result<CacheService, CacheError>> => { |
| 99 | const clientResult = await createRedisClientFromEnv(); |
| 100 | if (!clientResult.ok) { |
| 101 | logger.error({ error: clientResult.error }, "Redis client creation failed"); |
| 102 | return err({ code: clientResult.error.code }); |
| 103 | } |
| 104 | |
| 105 | const client = clientResult.data; |
| 106 | logger.debug("Redis connection established"); |
| 107 | const svc = new CacheService(client); |
| 108 | singleton = svc; |
| 109 | globalForCache.formbricksCache = svc; |
| 110 | logger.debug("Cache service created"); |
| 111 | return ok(svc); |
| 112 | })(); |
| 113 | |
| 114 | const result = await globalForCache.formbricksCacheInitializing; |
| 115 | if (!result.ok) { |
| 116 | globalForCache.formbricksCacheInitializing = undefined; // Allow retry |
| 117 | logger.error({ error: result.error }, "Cache service creation failed"); |
| 118 | } |
| 119 | return result; |
| 120 | } |
| 121 | |
| 122 | export function resetCacheFactory(): void { |
| 123 | singleton = null; |