1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-01 13:47:27 +02:00

feat: start tracking database calls for lifecycle (#10582)

Start tracking db calls for lifecycle store.
This commit is contained in:
Jaanus Sellin 2025-09-01 12:19:27 +03:00 committed by GitHub
parent c7cb5465ff
commit a1a43d1177
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 31 additions and 4 deletions

View File

@ -180,7 +180,7 @@ export const createStores = (
segmentReadModel: new SegmentReadModel(db),
projectOwnersReadModel: new ProjectOwnersReadModel(db),
projectFlagCreatorsReadModel: new ProjectFlagCreatorsReadModel(db),
featureLifecycleStore: new FeatureLifecycleStore(db),
featureLifecycleStore: new FeatureLifecycleStore(db, eventBus),
featureStrategiesReadModel: new FeatureStrategiesReadModel(db),
onboardingReadModel: createOnboardingReadModel(db),
onboardingStore: new OnboardingStore(db),

View File

@ -18,7 +18,7 @@ export const createFeatureLifecycleService =
(config: IUnleashConfig) => (db: Db) => {
const { eventBus, getLogger } = config;
const eventStore = new EventStore(db, getLogger);
const featureLifecycleStore = new FeatureLifecycleStore(db);
const featureLifecycleStore = new FeatureLifecycleStore(db, eventBus);
const environmentStore = new EnvironmentStore(db, eventBus, config);
const featureEnvironmentStore = new FeatureEnvironmentStore(
db,

View File

@ -7,6 +7,9 @@ import type {
} from './feature-lifecycle-store-type.js';
import type { Db } from '../../db/db.js';
import type { StageName } from '../../types/index.js';
import type EventEmitter from 'events';
import metricsHelper from '../../util/metrics-helper.js';
import { DB_TIME } from '../../metric-events.js';
type DBType = {
stage: StageName;
@ -23,11 +26,19 @@ type DBProjectType = DBType & {
export class FeatureLifecycleStore implements IFeatureLifecycleStore {
private db: Db;
constructor(db: Db) {
private timer: (string) => any;
constructor(db: Db, eventBus: EventEmitter) {
this.db = db;
this.timer = (action) =>
metricsHelper.wrapTimer(eventBus, DB_TIME, {
store: 'feature-lifecycle',
action,
});
}
async backfill(): Promise<void> {
const stopTimer = this.timer('backfill');
await this.db.raw(`
INSERT INTO feature_lifecycles (feature, stage, created_at)
SELECT features.name, 'initial', features.created_at
@ -43,11 +54,13 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
WHERE features.archived_at IS NOT NULL
AND feature_lifecycles.feature IS NULL
`);
stopTimer();
}
async insert(
featureLifecycleStages: FeatureLifecycleStage[],
): Promise<NewStage[]> {
const stopTimer = this.timer('insert');
const existingFeatures = await this.db('features')
.select('name')
.whereIn(
@ -62,6 +75,7 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
);
if (validStages.length === 0) {
stopTimer();
return [];
}
const result = await this.db('feature_lifecycles')
@ -78,6 +92,7 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
.onConflict(['feature', 'stage'])
.ignore();
stopTimer();
return result.map((row) => ({
stage: row.stage,
feature: row.feature,
@ -85,9 +100,11 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
}
async get(feature: string): Promise<FeatureLifecycleView> {
const stopTimer = this.timer('get');
const results = await this.db('feature_lifecycles')
.where({ feature })
.orderBy('created_at', 'asc');
stopTimer();
return results.map(({ stage, status, created_at }: DBType) => ({
stage,
@ -97,10 +114,12 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
}
async getAll(): Promise<FeatureLifecycleProjectItem[]> {
const stopTimer = this.timer('getAll');
const results = await this.db('feature_lifecycles as flc')
.select('flc.feature', 'flc.stage', 'flc.created_at', 'f.project')
.leftJoin('features as f', 'f.name', 'flc.feature')
.orderBy('created_at', 'asc');
stopTimer();
return results.map(
({ feature, stage, created_at, project }: DBProjectType) => ({
@ -113,27 +132,35 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
}
async delete(feature: string): Promise<void> {
const stopTimer = this.timer('delete');
await this.db('feature_lifecycles').where({ feature }).del();
stopTimer();
}
async deleteAll(): Promise<void> {
const stopTimer = this.timer('deleteAll');
await this.db('feature_lifecycles').del();
stopTimer();
}
async deleteStage(stage: FeatureLifecycleStage): Promise<void> {
const stopTimer = this.timer('deleteStage');
await this.db('feature_lifecycles')
.where({
stage: stage.stage,
feature: stage.feature,
})
.del();
stopTimer();
}
async stageExists(stage: FeatureLifecycleStage): Promise<boolean> {
const stopTimer = this.timer('stageExists');
const result = await this.db.raw(
`SELECT EXISTS(SELECT 1 FROM feature_lifecycles WHERE stage = ? and feature = ?) AS present`,
[stage.stage, stage.feature],
);
stopTimer();
const { present } = result.rows[0];
return present;
}

View File

@ -69,7 +69,7 @@ beforeAll(async () => {
featureLifeCycleReadModel = new FeatureLifecycleReadModel(db.rawDatabase);
stores.featureLifecycleReadModel = featureLifeCycleReadModel;
featureLifeCycleStore = new FeatureLifecycleStore(db.rawDatabase);
featureLifeCycleStore = new FeatureLifecycleStore(db.rawDatabase, eventBus);
stores.featureLifecycleStore = featureLifeCycleStore;
statsService = new InstanceStatsService(