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

feat: transactional complete/uncomplete feature (#7451)

This commit is contained in:
Mateusz Kwasniewski 2024-06-26 09:05:17 +02:00 committed by GitHub
parent 7f6e29b5dd
commit d29230cd49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 53 additions and 59 deletions

View File

@ -14,48 +14,41 @@ import { FeatureEnvironmentStore } from '../../db/feature-environment-store';
import FakeFeatureEnvironmentStore from '../../../test/fixtures/fake-feature-environment-store'; import FakeFeatureEnvironmentStore from '../../../test/fixtures/fake-feature-environment-store';
import EventEmitter from 'events'; import EventEmitter from 'events';
export const createFeatureLifecycleService = ( export const createFeatureLifecycleService =
db: Db, (config: IUnleashConfig) => (db: Db) => {
config: IUnleashConfig, const { eventBus, getLogger, flagResolver } = config;
) => { const eventStore = new EventStore(db, getLogger);
const { eventBus, getLogger, flagResolver } = config; const featureLifecycleStore = new FeatureLifecycleStore(db);
const eventStore = new EventStore(db, getLogger); const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
const featureLifecycleStore = new FeatureLifecycleStore(db); const featureEnvironmentStore = new FeatureEnvironmentStore(
const environmentStore = new EnvironmentStore(db, eventBus, getLogger); db,
const featureEnvironmentStore = new FeatureEnvironmentStore( eventBus,
db, getLogger,
eventBus, );
getLogger, const featureTagStore = new FeatureTagStore(
); db,
const featureTagStore = new FeatureTagStore( config.eventBus,
db, config.getLogger,
config.eventBus, );
config.getLogger, const eventService = new EventService(
); { eventStore, featureTagStore },
const eventService = new EventService( { getLogger, eventBus: new EventEmitter() },
{ eventStore, featureTagStore }, );
{ getLogger, eventBus: new EventEmitter() }, const featureLifecycleService = new FeatureLifecycleService(
); {
const featureLifecycleService = new FeatureLifecycleService( eventStore,
{ featureLifecycleStore,
eventStore, environmentStore,
featureLifecycleStore, featureEnvironmentStore,
environmentStore, },
featureEnvironmentStore, {
}, eventService,
{ },
eventService, config,
}, );
config,
);
return { return featureLifecycleService;
featureLifecycleService,
featureLifecycleStore,
eventStore,
environmentStore,
}; };
};
export const createFakeFeatureLifecycleService = (config: IUnleashConfig) => { export const createFakeFeatureLifecycleService = (config: IUnleashConfig) => {
const eventStore = new FakeEventStore(); const eventStore = new FakeEventStore();

View File

@ -21,6 +21,7 @@ import Controller from '../../routes/controller';
import type { Request, Response } from 'express'; import type { Request, Response } from 'express';
import { NotFoundError } from '../../error'; import { NotFoundError } from '../../error';
import type { IAuthRequest } from '../../routes/unleash-types'; import type { IAuthRequest } from '../../routes/unleash-types';
import type { WithTransactional } from '../../db/transaction';
interface FeatureLifecycleParams { interface FeatureLifecycleParams {
projectId: string; projectId: string;
@ -30,7 +31,7 @@ interface FeatureLifecycleParams {
const PATH = '/:projectId/features/:featureName/lifecycle'; const PATH = '/:projectId/features/:featureName/lifecycle';
export default class FeatureLifecycleController extends Controller { export default class FeatureLifecycleController extends Controller {
private featureLifecycleService: FeatureLifecycleService; private featureLifecycleService: WithTransactional<FeatureLifecycleService>;
private openApiService: OpenApiService; private openApiService: OpenApiService;
@ -39,12 +40,15 @@ export default class FeatureLifecycleController extends Controller {
constructor( constructor(
config: IUnleashConfig, config: IUnleashConfig,
{ {
featureLifecycleService, transactionalFeatureLifecycleService,
openApiService, openApiService,
}: Pick<IUnleashServices, 'openApiService' | 'featureLifecycleService'>, }: Pick<
IUnleashServices,
'openApiService' | 'transactionalFeatureLifecycleService'
>,
) { ) {
super(config); super(config);
this.featureLifecycleService = featureLifecycleService; this.featureLifecycleService = transactionalFeatureLifecycleService;
this.openApiService = openApiService; this.openApiService = openApiService;
this.flagResolver = config.flagResolver; this.flagResolver = config.flagResolver;
@ -147,11 +151,8 @@ export default class FeatureLifecycleController extends Controller {
const status = req.body; const status = req.body;
await this.featureLifecycleService.featureCompleted( await this.featureLifecycleService.transactional((service) =>
featureName, service.featureCompleted(featureName, projectId, status, req.audit),
projectId,
status,
req.audit,
); );
res.status(200).end(); res.status(200).end();
@ -166,10 +167,8 @@ export default class FeatureLifecycleController extends Controller {
} }
const { featureName, projectId } = req.params; const { featureName, projectId } = req.params;
await this.featureLifecycleService.featureUncompleted( await this.featureLifecycleService.transactional((service) =>
featureName, service.featureUncompleted(featureName, projectId, req.audit),
projectId,
req.audit,
); );
res.status(200).end(); res.status(200).end();

View File

@ -14,7 +14,6 @@ import {
type StageName, type StageName,
} from '../../types'; } from '../../types';
import type EventEmitter from 'events'; import type EventEmitter from 'events';
import type { FeatureLifecycleService } from './feature-lifecycle-service';
import type { FeatureLifecycleCompletedSchema } from '../../openapi'; import type { FeatureLifecycleCompletedSchema } from '../../openapi';
import { FeatureLifecycleReadModel } from './feature-lifecycle-read-model'; import { FeatureLifecycleReadModel } from './feature-lifecycle-read-model';
import type { IFeatureLifecycleReadModel } from './feature-lifecycle-read-model-type'; import type { IFeatureLifecycleReadModel } from './feature-lifecycle-read-model-type';
@ -22,7 +21,6 @@ import { STAGE_ENTERED } from '../../metric-events';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
let featureLifecycleService: FeatureLifecycleService;
let featureLifecycleStore: IFeatureLifecycleStore; let featureLifecycleStore: IFeatureLifecycleStore;
let eventStore: IEventStore; let eventStore: IEventStore;
let eventBus: EventEmitter; let eventBus: EventEmitter;
@ -43,7 +41,6 @@ beforeAll(async () => {
); );
eventStore = db.stores.eventStore; eventStore = db.stores.eventStore;
eventBus = app.config.eventBus; eventBus = app.config.eventBus;
featureLifecycleService = app.services.featureLifecycleService;
featureLifecycleReadModel = new FeatureLifecycleReadModel( featureLifecycleReadModel = new FeatureLifecycleReadModel(
db.rawDatabase, db.rawDatabase,
app.config.flagResolver, app.config.flagResolver,

View File

@ -362,9 +362,12 @@ export const createServices = (
config.getLogger, config.getLogger,
); );
const { featureLifecycleService } = db const transactionalFeatureLifecycleService = db
? createFeatureLifecycleService(db, config) ? withTransactional(createFeatureLifecycleService(config), db)
: createFakeFeatureLifecycleService(config); : withFakeTransactional(
createFakeFeatureLifecycleService(config).featureLifecycleService,
);
const featureLifecycleService = transactionalFeatureLifecycleService;
featureLifecycleService.listen(); featureLifecycleService.listen();
return { return {
@ -426,6 +429,7 @@ export const createServices = (
projectInsightsService, projectInsightsService,
jobService, jobService,
featureLifecycleService, featureLifecycleService,
transactionalFeatureLifecycleService,
}; };
}; };

View File

@ -117,4 +117,5 @@ export interface IUnleashServices {
projectInsightsService: ProjectInsightsService; projectInsightsService: ProjectInsightsService;
jobService: JobService; jobService: JobService;
featureLifecycleService: FeatureLifecycleService; featureLifecycleService: FeatureLifecycleService;
transactionalFeatureLifecycleService: WithTransactional<FeatureLifecycleService>;
} }