Skip to content

Commit

Permalink
feat: revived feature goes to initial lifecycle stage (#6944)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew committed Apr 26, 2024
1 parent 675e1a9 commit 8ed1516
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export class FakeFeatureLifecycleStore implements IFeatureLifecycleStore {
return this.lifecycles[feature] || [];
}

async delete(feature: string): Promise<void> {
this.lifecycles[feature] = [];
}

async stageExists(stage: FeatureLifecycleStage): Promise<boolean> {
const lifecycle = await this.get(stage.feature);
return Boolean(lifecycle.find((s) => s.stage === stage.stage));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
FEATURE_ARCHIVED,
FEATURE_COMPLETED,
FEATURE_CREATED,
FEATURE_REVIVED,
type IEnvironment,
type IUnleashConfig,
type StageName,
Expand Down Expand Up @@ -82,6 +83,14 @@ test('can insert and read lifecycle stages', async () => {
{ stage: 'completed', enteredStageAt: expect.any(Date) },
{ stage: 'archived', enteredStageAt: expect.any(Date) },
]);

eventStore.emit(FEATURE_REVIVED, { featureName });
await reachedStage('initial');
const initialLifecycle =
await featureLifecycleService.getFeatureLifecycle(featureName);
expect(initialLifecycle).toEqual([
{ stage: 'initial', enteredStageAt: expect.any(Date) },
]);
});

test('ignores lifecycle state updates when flag disabled', async () => {
Expand Down
11 changes: 11 additions & 0 deletions src/lib/features/feature-lifecycle/feature-lifecycle-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
FEATURE_ARCHIVED,
FEATURE_COMPLETED,
FEATURE_CREATED,
FEATURE_REVIVED,
type IEnvironmentStore,
type IEventStore,
type IFlagResolver,
Expand Down Expand Up @@ -93,6 +94,11 @@ export class FeatureLifecycleService extends EventEmitter {
this.featureArchived(event.featureName),
);
});
this.eventStore.on(FEATURE_REVIVED, async (event) => {
await this.checkEnabled(() =>
this.featureRevived(event.featureName),
);
});
}

async getFeatureLifecycle(feature: string): Promise<FeatureLifecycleView> {
Expand Down Expand Up @@ -155,4 +161,9 @@ export class FeatureLifecycleService extends EventEmitter {
]);
this.emit(STAGE_ENTERED, { stage: 'archived' });
}

private async featureRevived(feature: string) {
await this.featureLifecycleStore.delete(feature);
await this.featureInitialized(feature);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export interface IFeatureLifecycleStore {
insert(featureLifecycleStages: FeatureLifecycleStage[]): Promise<void>;
get(feature: string): Promise<FeatureLifecycleView>;
stageExists(stage: FeatureLifecycleStage): Promise<boolean>;
delete(feature: string): Promise<void>;
}
4 changes: 4 additions & 0 deletions src/lib/features/feature-lifecycle/feature-lifecycle-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
}));
}

async delete(feature: string): Promise<void> {
await this.db('feature_lifecycles').where({ feature }).del();
}

async stageExists(stage: FeatureLifecycleStage): Promise<boolean> {
const result = await this.db.raw(
`SELECT EXISTS(SELECT 1 FROM feature_lifecycles WHERE stage = ? and feature = ?) AS present`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
CLIENT_METRICS,
FEATURE_ARCHIVED,
FEATURE_CREATED,
FEATURE_REVIVED,
type IEventStore,
type StageName,
} from '../../types';
Expand Down Expand Up @@ -117,4 +118,7 @@ test('should return lifecycle stages', async () => {
]);

await expectFeatureStage('archived');

eventStore.emit(FEATURE_REVIVED, { featureName: 'my_feature_a' });
await reachedStage('initial');
});

0 comments on commit 8ed1516

Please sign in to comment.