diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts b/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts index 8da4a8e7b3..c4380820a7 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts @@ -10,6 +10,7 @@ import { createFakeFeatureLifecycleService } from './createFeatureLifecycle'; import EventEmitter from 'events'; import type { StageName } from './feature-lifecycle-store-type'; import { STAGE_ENTERED } from './feature-lifecycle-service'; +import noLoggerProvider from '../../../test/fixtures/no-logger'; test('can insert and read lifecycle stages', async () => { const eventBus = new EventEmitter(); @@ -17,6 +18,7 @@ test('can insert and read lifecycle stages', async () => { createFakeFeatureLifecycleService({ flagResolver: { isEnabled: () => true }, eventBus, + getLogger: noLoggerProvider, } as unknown as IUnleashConfig); const featureName = 'testFeature'; @@ -85,6 +87,7 @@ test('ignores lifecycle state updates when flag disabled', async () => { createFakeFeatureLifecycleService({ flagResolver: { isEnabled: () => false }, eventBus, + getLogger: noLoggerProvider, } as unknown as IUnleashConfig); const featureName = 'testFeature'; diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts b/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts index fb2af58a15..7ebf6e706f 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts @@ -13,6 +13,7 @@ import type { IFeatureLifecycleStore, } from './feature-lifecycle-store-type'; import EventEmitter from 'events'; +import type { Logger } from '../../logger'; export const STAGE_ENTERED = 'STAGE_ENTERED'; @@ -27,6 +28,8 @@ export class FeatureLifecycleService extends EventEmitter { private eventBus: EventEmitter; + private logger: Logger; + constructor( { eventStore, @@ -40,7 +43,8 @@ export class FeatureLifecycleService extends EventEmitter { { flagResolver, eventBus, - }: Pick, + getLogger, + }: Pick, ) { super(); this.eventStore = eventStore; @@ -48,6 +52,9 @@ export class FeatureLifecycleService extends EventEmitter { this.environmentStore = environmentStore; this.flagResolver = flagResolver; this.eventBus = eventBus; + this.logger = getLogger( + 'feature-lifecycle/feature-lifecycle-service.ts', + ); } private async checkEnabled(fn: () => Promise) { @@ -64,6 +71,7 @@ export class FeatureLifecycleService extends EventEmitter { ); }); this.eventBus.on(CLIENT_METRICS, async (event) => { + if (!event.featureName || !event.environment) return; await this.checkEnabled(() => this.featureReceivedMetrics( event.featureName, @@ -107,14 +115,22 @@ export class FeatureLifecycleService extends EventEmitter { } private async featureReceivedMetrics(feature: string, environment: string) { - const env = await this.environmentStore.get(environment); - if (!env) { - return; - } - if (env.type === 'production') { - await this.stageReceivedMetrics(feature, 'live'); - } else if (env.type === 'development') { - await this.stageReceivedMetrics(feature, 'pre-live'); + try { + const env = await this.environmentStore.get(environment); + + if (!env) { + return; + } + if (env.type === 'production') { + await this.stageReceivedMetrics(feature, 'live'); + } else if (env.type === 'development') { + await this.stageReceivedMetrics(feature, 'pre-live'); + } + } catch (e) { + this.logger.warn( + `Error handling metrics for ${feature} in ${environment}`, + e, + ); } } diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts b/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts index dec8c4aa75..e724b2941e 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts @@ -77,6 +77,15 @@ test('should return lifecycle stages', async () => { featureName: 'my_feature_a', environment: 'default', }); + // missing feature + eventBus.emit(CLIENT_METRICS, { + environment: 'default', + }); + // non existent env + eventBus.emit(CLIENT_METRICS, { + featureName: 'my_feature_a', + environment: 'non-existent', + }); await reachedStage('live'); eventStore.emit(FEATURE_ARCHIVED, { featureName: 'my_feature_a' }); await reachedStage('archived');