import type { Logger } from '../../logger.js'; import type { IEventStore, IFlagResolver, IUnleashConfig, IUnleashStores, } from '../../types/index.js'; import EventEmitter from 'events'; export const UPDATE_REVISION = 'UPDATE_REVISION'; export default class ConfigurationRevisionService extends EventEmitter { private static instance: ConfigurationRevisionService | undefined; private logger: Logger; private eventStore: IEventStore; private revisionId: number; private maxRevisionId: Map = new Map(); private flagResolver: IFlagResolver; private constructor( { eventStore }: Pick, { getLogger, flagResolver, }: Pick, ) { super(); this.logger = getLogger('configuration-revision-service.ts'); this.eventStore = eventStore; this.flagResolver = flagResolver; this.revisionId = 0; } static getInstance( { eventStore }: Pick, { getLogger, flagResolver, }: Pick, ) { if (!ConfigurationRevisionService.instance) { ConfigurationRevisionService.instance = new ConfigurationRevisionService( { eventStore }, { getLogger, flagResolver }, ); } return ConfigurationRevisionService.instance; } async getMaxRevisionId(environment?: string): Promise { if (environment && !this.maxRevisionId[environment]) { await this.updateMaxEnvironmentRevisionId(environment); } if ( environment && this.maxRevisionId[environment] && this.maxRevisionId[environment] > 0 ) { return this.maxRevisionId[environment]; } if (this.revisionId > 0) { return this.revisionId; } else { return this.updateMaxRevisionId(); } } async updateMaxEnvironmentRevisionId(environment: string): Promise { const envRevisionId = await this.eventStore.getMaxRevisionId( this.maxRevisionId[environment], environment, ); if (this.maxRevisionId[environment] ?? 0 < envRevisionId) { this.maxRevisionId[environment] = envRevisionId; } return this.maxRevisionId[environment]; } async updateMaxRevisionId(emit: boolean = true): Promise { if (this.flagResolver.isEnabled('disableUpdateMaxRevisionId')) { return 0; } const revisionId = await this.eventStore.getMaxRevisionId( this.revisionId, ); if (this.revisionId !== revisionId) { this.logger.debug( `Updating feature configuration with new revision Id ${revisionId} and all envs: ${Object.keys(this.maxRevisionId).join(', ')}`, ); await Promise.allSettled( Object.keys(this.maxRevisionId).map((environment) => this.updateMaxEnvironmentRevisionId(environment), ), ); this.revisionId = revisionId; if (emit) { this.emit(UPDATE_REVISION, revisionId); } } return this.revisionId; } destroy(): void { ConfigurationRevisionService.instance?.removeAllListeners(); ConfigurationRevisionService.instance = undefined; } }