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:
parent
c7cb5465ff
commit
a1a43d1177
@ -180,7 +180,7 @@ export const createStores = (
|
|||||||
segmentReadModel: new SegmentReadModel(db),
|
segmentReadModel: new SegmentReadModel(db),
|
||||||
projectOwnersReadModel: new ProjectOwnersReadModel(db),
|
projectOwnersReadModel: new ProjectOwnersReadModel(db),
|
||||||
projectFlagCreatorsReadModel: new ProjectFlagCreatorsReadModel(db),
|
projectFlagCreatorsReadModel: new ProjectFlagCreatorsReadModel(db),
|
||||||
featureLifecycleStore: new FeatureLifecycleStore(db),
|
featureLifecycleStore: new FeatureLifecycleStore(db, eventBus),
|
||||||
featureStrategiesReadModel: new FeatureStrategiesReadModel(db),
|
featureStrategiesReadModel: new FeatureStrategiesReadModel(db),
|
||||||
onboardingReadModel: createOnboardingReadModel(db),
|
onboardingReadModel: createOnboardingReadModel(db),
|
||||||
onboardingStore: new OnboardingStore(db),
|
onboardingStore: new OnboardingStore(db),
|
||||||
|
@ -18,7 +18,7 @@ export const createFeatureLifecycleService =
|
|||||||
(config: IUnleashConfig) => (db: Db) => {
|
(config: IUnleashConfig) => (db: Db) => {
|
||||||
const { eventBus, getLogger } = config;
|
const { eventBus, getLogger } = config;
|
||||||
const eventStore = new EventStore(db, getLogger);
|
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 environmentStore = new EnvironmentStore(db, eventBus, config);
|
||||||
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
||||||
db,
|
db,
|
||||||
|
@ -7,6 +7,9 @@ import type {
|
|||||||
} from './feature-lifecycle-store-type.js';
|
} from './feature-lifecycle-store-type.js';
|
||||||
import type { Db } from '../../db/db.js';
|
import type { Db } from '../../db/db.js';
|
||||||
import type { StageName } from '../../types/index.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 = {
|
type DBType = {
|
||||||
stage: StageName;
|
stage: StageName;
|
||||||
@ -23,11 +26,19 @@ type DBProjectType = DBType & {
|
|||||||
export class FeatureLifecycleStore implements IFeatureLifecycleStore {
|
export class FeatureLifecycleStore implements IFeatureLifecycleStore {
|
||||||
private db: Db;
|
private db: Db;
|
||||||
|
|
||||||
constructor(db: Db) {
|
private timer: (string) => any;
|
||||||
|
|
||||||
|
constructor(db: Db, eventBus: EventEmitter) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
|
this.timer = (action) =>
|
||||||
|
metricsHelper.wrapTimer(eventBus, DB_TIME, {
|
||||||
|
store: 'feature-lifecycle',
|
||||||
|
action,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async backfill(): Promise<void> {
|
async backfill(): Promise<void> {
|
||||||
|
const stopTimer = this.timer('backfill');
|
||||||
await this.db.raw(`
|
await this.db.raw(`
|
||||||
INSERT INTO feature_lifecycles (feature, stage, created_at)
|
INSERT INTO feature_lifecycles (feature, stage, created_at)
|
||||||
SELECT features.name, 'initial', features.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
|
WHERE features.archived_at IS NOT NULL
|
||||||
AND feature_lifecycles.feature IS NULL
|
AND feature_lifecycles.feature IS NULL
|
||||||
`);
|
`);
|
||||||
|
stopTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
async insert(
|
async insert(
|
||||||
featureLifecycleStages: FeatureLifecycleStage[],
|
featureLifecycleStages: FeatureLifecycleStage[],
|
||||||
): Promise<NewStage[]> {
|
): Promise<NewStage[]> {
|
||||||
|
const stopTimer = this.timer('insert');
|
||||||
const existingFeatures = await this.db('features')
|
const existingFeatures = await this.db('features')
|
||||||
.select('name')
|
.select('name')
|
||||||
.whereIn(
|
.whereIn(
|
||||||
@ -62,6 +75,7 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (validStages.length === 0) {
|
if (validStages.length === 0) {
|
||||||
|
stopTimer();
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const result = await this.db('feature_lifecycles')
|
const result = await this.db('feature_lifecycles')
|
||||||
@ -78,6 +92,7 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
|
|||||||
.onConflict(['feature', 'stage'])
|
.onConflict(['feature', 'stage'])
|
||||||
.ignore();
|
.ignore();
|
||||||
|
|
||||||
|
stopTimer();
|
||||||
return result.map((row) => ({
|
return result.map((row) => ({
|
||||||
stage: row.stage,
|
stage: row.stage,
|
||||||
feature: row.feature,
|
feature: row.feature,
|
||||||
@ -85,9 +100,11 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async get(feature: string): Promise<FeatureLifecycleView> {
|
async get(feature: string): Promise<FeatureLifecycleView> {
|
||||||
|
const stopTimer = this.timer('get');
|
||||||
const results = await this.db('feature_lifecycles')
|
const results = await this.db('feature_lifecycles')
|
||||||
.where({ feature })
|
.where({ feature })
|
||||||
.orderBy('created_at', 'asc');
|
.orderBy('created_at', 'asc');
|
||||||
|
stopTimer();
|
||||||
|
|
||||||
return results.map(({ stage, status, created_at }: DBType) => ({
|
return results.map(({ stage, status, created_at }: DBType) => ({
|
||||||
stage,
|
stage,
|
||||||
@ -97,10 +114,12 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getAll(): Promise<FeatureLifecycleProjectItem[]> {
|
async getAll(): Promise<FeatureLifecycleProjectItem[]> {
|
||||||
|
const stopTimer = this.timer('getAll');
|
||||||
const results = await this.db('feature_lifecycles as flc')
|
const results = await this.db('feature_lifecycles as flc')
|
||||||
.select('flc.feature', 'flc.stage', 'flc.created_at', 'f.project')
|
.select('flc.feature', 'flc.stage', 'flc.created_at', 'f.project')
|
||||||
.leftJoin('features as f', 'f.name', 'flc.feature')
|
.leftJoin('features as f', 'f.name', 'flc.feature')
|
||||||
.orderBy('created_at', 'asc');
|
.orderBy('created_at', 'asc');
|
||||||
|
stopTimer();
|
||||||
|
|
||||||
return results.map(
|
return results.map(
|
||||||
({ feature, stage, created_at, project }: DBProjectType) => ({
|
({ feature, stage, created_at, project }: DBProjectType) => ({
|
||||||
@ -113,27 +132,35 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async delete(feature: string): Promise<void> {
|
async delete(feature: string): Promise<void> {
|
||||||
|
const stopTimer = this.timer('delete');
|
||||||
await this.db('feature_lifecycles').where({ feature }).del();
|
await this.db('feature_lifecycles').where({ feature }).del();
|
||||||
|
stopTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteAll(): Promise<void> {
|
async deleteAll(): Promise<void> {
|
||||||
|
const stopTimer = this.timer('deleteAll');
|
||||||
await this.db('feature_lifecycles').del();
|
await this.db('feature_lifecycles').del();
|
||||||
|
stopTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteStage(stage: FeatureLifecycleStage): Promise<void> {
|
async deleteStage(stage: FeatureLifecycleStage): Promise<void> {
|
||||||
|
const stopTimer = this.timer('deleteStage');
|
||||||
await this.db('feature_lifecycles')
|
await this.db('feature_lifecycles')
|
||||||
.where({
|
.where({
|
||||||
stage: stage.stage,
|
stage: stage.stage,
|
||||||
feature: stage.feature,
|
feature: stage.feature,
|
||||||
})
|
})
|
||||||
.del();
|
.del();
|
||||||
|
stopTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
async stageExists(stage: FeatureLifecycleStage): Promise<boolean> {
|
async stageExists(stage: FeatureLifecycleStage): Promise<boolean> {
|
||||||
|
const stopTimer = this.timer('stageExists');
|
||||||
const result = await this.db.raw(
|
const result = await this.db.raw(
|
||||||
`SELECT EXISTS(SELECT 1 FROM feature_lifecycles WHERE stage = ? and feature = ?) AS present`,
|
`SELECT EXISTS(SELECT 1 FROM feature_lifecycles WHERE stage = ? and feature = ?) AS present`,
|
||||||
[stage.stage, stage.feature],
|
[stage.stage, stage.feature],
|
||||||
);
|
);
|
||||||
|
stopTimer();
|
||||||
const { present } = result.rows[0];
|
const { present } = result.rows[0];
|
||||||
return present;
|
return present;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ beforeAll(async () => {
|
|||||||
|
|
||||||
featureLifeCycleReadModel = new FeatureLifecycleReadModel(db.rawDatabase);
|
featureLifeCycleReadModel = new FeatureLifecycleReadModel(db.rawDatabase);
|
||||||
stores.featureLifecycleReadModel = featureLifeCycleReadModel;
|
stores.featureLifecycleReadModel = featureLifeCycleReadModel;
|
||||||
featureLifeCycleStore = new FeatureLifecycleStore(db.rawDatabase);
|
featureLifeCycleStore = new FeatureLifecycleStore(db.rawDatabase, eventBus);
|
||||||
stores.featureLifecycleStore = featureLifeCycleStore;
|
stores.featureLifecycleStore = featureLifeCycleStore;
|
||||||
|
|
||||||
statsService = new InstanceStatsService(
|
statsService = new InstanceStatsService(
|
||||||
|
Loading…
Reference in New Issue
Block a user