import { Injectable, OnModuleDestroy } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import Redis from 'ioredis'; import type { BuildProgress } from './build.service'; const KEY_PREFIX = 'build:progress:'; const TTL_SECONDS = 3600; @Injectable() export class BuildProgressStore implements OnModuleDestroy { private readonly redis: Redis; constructor(private readonly configService: ConfigService) { this.redis = new Redis({ host: this.configService.get('redis.host'), port: this.configService.get('redis.port'), lazyConnect: true, maxRetriesPerRequest: 1, }); this.redis.connect().catch(() => { // Redis may be unavailable in local unit tests — in-memory fallback remains in BuildService. }); } async get(deploymentId: string): Promise { try { const raw = await this.redis.get(`${KEY_PREFIX}${deploymentId}`); return raw ? (JSON.parse(raw) as BuildProgress) : null; } catch { return null; } } async set(deploymentId: string, progress: BuildProgress): Promise { try { await this.redis.set( `${KEY_PREFIX}${deploymentId}`, JSON.stringify(progress), 'EX', TTL_SECONDS, ); } catch { // Best-effort — local map still holds progress for this replica. } } async clear(deploymentId: string): Promise { try { await this.redis.del(`${KEY_PREFIX}${deploymentId}`); } catch { // ignore } } onModuleDestroy(): void { this.redis.disconnect(); } }