1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-31 00:16:47 +01:00

feat: handle invalid metrics (#6795)

This commit is contained in:
Mateusz Kwasniewski 2024-04-08 12:09:20 +02:00 committed by GitHub
parent 9dc9fb3586
commit 7cb9910b05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 37 additions and 9 deletions

View File

@ -10,6 +10,7 @@ import { createFakeFeatureLifecycleService } from './createFeatureLifecycle';
import EventEmitter from 'events'; import EventEmitter from 'events';
import type { StageName } from './feature-lifecycle-store-type'; import type { StageName } from './feature-lifecycle-store-type';
import { STAGE_ENTERED } from './feature-lifecycle-service'; import { STAGE_ENTERED } from './feature-lifecycle-service';
import noLoggerProvider from '../../../test/fixtures/no-logger';
test('can insert and read lifecycle stages', async () => { test('can insert and read lifecycle stages', async () => {
const eventBus = new EventEmitter(); const eventBus = new EventEmitter();
@ -17,6 +18,7 @@ test('can insert and read lifecycle stages', async () => {
createFakeFeatureLifecycleService({ createFakeFeatureLifecycleService({
flagResolver: { isEnabled: () => true }, flagResolver: { isEnabled: () => true },
eventBus, eventBus,
getLogger: noLoggerProvider,
} as unknown as IUnleashConfig); } as unknown as IUnleashConfig);
const featureName = 'testFeature'; const featureName = 'testFeature';
@ -85,6 +87,7 @@ test('ignores lifecycle state updates when flag disabled', async () => {
createFakeFeatureLifecycleService({ createFakeFeatureLifecycleService({
flagResolver: { isEnabled: () => false }, flagResolver: { isEnabled: () => false },
eventBus, eventBus,
getLogger: noLoggerProvider,
} as unknown as IUnleashConfig); } as unknown as IUnleashConfig);
const featureName = 'testFeature'; const featureName = 'testFeature';

View File

@ -13,6 +13,7 @@ import type {
IFeatureLifecycleStore, IFeatureLifecycleStore,
} from './feature-lifecycle-store-type'; } from './feature-lifecycle-store-type';
import EventEmitter from 'events'; import EventEmitter from 'events';
import type { Logger } from '../../logger';
export const STAGE_ENTERED = 'STAGE_ENTERED'; export const STAGE_ENTERED = 'STAGE_ENTERED';
@ -27,6 +28,8 @@ export class FeatureLifecycleService extends EventEmitter {
private eventBus: EventEmitter; private eventBus: EventEmitter;
private logger: Logger;
constructor( constructor(
{ {
eventStore, eventStore,
@ -40,7 +43,8 @@ export class FeatureLifecycleService extends EventEmitter {
{ {
flagResolver, flagResolver,
eventBus, eventBus,
}: Pick<IUnleashConfig, 'flagResolver' | 'eventBus'>, getLogger,
}: Pick<IUnleashConfig, 'flagResolver' | 'eventBus' | 'getLogger'>,
) { ) {
super(); super();
this.eventStore = eventStore; this.eventStore = eventStore;
@ -48,6 +52,9 @@ export class FeatureLifecycleService extends EventEmitter {
this.environmentStore = environmentStore; this.environmentStore = environmentStore;
this.flagResolver = flagResolver; this.flagResolver = flagResolver;
this.eventBus = eventBus; this.eventBus = eventBus;
this.logger = getLogger(
'feature-lifecycle/feature-lifecycle-service.ts',
);
} }
private async checkEnabled(fn: () => Promise<void>) { private async checkEnabled(fn: () => Promise<void>) {
@ -64,6 +71,7 @@ export class FeatureLifecycleService extends EventEmitter {
); );
}); });
this.eventBus.on(CLIENT_METRICS, async (event) => { this.eventBus.on(CLIENT_METRICS, async (event) => {
if (!event.featureName || !event.environment) return;
await this.checkEnabled(() => await this.checkEnabled(() =>
this.featureReceivedMetrics( this.featureReceivedMetrics(
event.featureName, event.featureName,
@ -107,7 +115,9 @@ export class FeatureLifecycleService extends EventEmitter {
} }
private async featureReceivedMetrics(feature: string, environment: string) { private async featureReceivedMetrics(feature: string, environment: string) {
try {
const env = await this.environmentStore.get(environment); const env = await this.environmentStore.get(environment);
if (!env) { if (!env) {
return; return;
} }
@ -116,6 +126,12 @@ export class FeatureLifecycleService extends EventEmitter {
} else if (env.type === 'development') { } else if (env.type === 'development') {
await this.stageReceivedMetrics(feature, 'pre-live'); await this.stageReceivedMetrics(feature, 'pre-live');
} }
} catch (e) {
this.logger.warn(
`Error handling metrics for ${feature} in ${environment}`,
e,
);
}
} }
private async featureCompleted(feature: string) { private async featureCompleted(feature: string) {

View File

@ -77,6 +77,15 @@ test('should return lifecycle stages', async () => {
featureName: 'my_feature_a', featureName: 'my_feature_a',
environment: 'default', 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'); await reachedStage('live');
eventStore.emit(FEATURE_ARCHIVED, { featureName: 'my_feature_a' }); eventStore.emit(FEATURE_ARCHIVED, { featureName: 'my_feature_a' });
await reachedStage('archived'); await reachedStage('archived');