1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-28 00:06:53 +01:00

feat: backfill current stage on startup (#7057)

This commit is contained in:
Mateusz Kwasniewski 2024-05-15 12:47:01 +02:00 committed by GitHub
parent 701c845f09
commit 6b59b30846
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 34 additions and 0 deletions

View File

@ -16,6 +16,8 @@ export class FakeFeatureLifecycleStore implements IFeatureLifecycleStore {
);
}
async backfill() {}
private async insertOne(
featureLifecycleStage: FeatureLifecycleStage,
): Promise<void> {

View File

@ -87,6 +87,7 @@ export class FeatureLifecycleService extends EventEmitter {
}
listen() {
void this.checkEnabled(() => this.featureLifecycleStore.backfill());
this.eventStore.on(FEATURE_CREATED, async (event) => {
await this.checkEnabled(() =>
this.featureInitialized(event.featureName),

View File

@ -21,4 +21,5 @@ export interface IFeatureLifecycleStore {
stageExists(stage: FeatureLifecycleStage): Promise<boolean>;
delete(feature: string): Promise<void>;
deleteStage(stage: FeatureLifecycleStage): Promise<void>;
backfill(): Promise<void>;
}

View File

@ -26,6 +26,16 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
this.db = db;
}
async backfill(): Promise<void> {
await this.db.raw(`
INSERT INTO feature_lifecycles (feature, stage, created_at)
SELECT features.name, 'initial', features.created_at
FROM features
LEFT JOIN feature_lifecycles ON features.name = feature_lifecycles.feature
WHERE feature_lifecycles.feature IS NULL
`);
}
async insert(
featureLifecycleStages: FeatureLifecycleStage[],
): Promise<void> {

View File

@ -10,6 +10,7 @@ import {
FEATURE_CREATED,
FEATURE_REVIVED,
type IEventStore,
type IFeatureLifecycleStore,
type StageName,
} from '../../types';
import type EventEmitter from 'events';
@ -24,6 +25,7 @@ import type { IFeatureLifecycleReadModel } from './feature-lifecycle-read-model-
let app: IUnleashTest;
let db: ITestDb;
let featureLifecycleService: FeatureLifecycleService;
let featureLifecycleStore: IFeatureLifecycleStore;
let eventStore: IEventStore;
let eventBus: EventEmitter;
let featureLifecycleReadModel: IFeatureLifecycleReadModel;
@ -45,6 +47,7 @@ beforeAll(async () => {
eventBus = app.config.eventBus;
featureLifecycleService = app.services.featureLifecycleService;
featureLifecycleReadModel = new FeatureLifecycleReadModel(db.rawDatabase);
featureLifecycleStore = db.stores.featureLifecycleStore;
await app.request
.post(`/auth/demo/login`)
@ -186,3 +189,20 @@ test('should be able to toggle between completed/uncompleted', async () => {
expect(body).toEqual([]);
});
test('should backfill initial stage when no stages', async () => {
await app.createFeature('my_feature_c');
await featureLifecycleStore.delete('my_feature_c');
const currentStage = await getCurrentStage('my_feature_c');
expect(currentStage).toBe(undefined);
await featureLifecycleStore.backfill();
const backfilledCurrentStage = await getCurrentStage('my_feature_c');
expect(backfilledCurrentStage).toEqual({
stage: 'initial',
enteredStageAt: expect.any(Date),
});
});