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

feat: dependent features use new transaction mechanism (#5073)

This commit is contained in:
Mateusz Kwasniewski 2023-10-18 08:59:26 +02:00 committed by GitHub
parent 4dd01c1765
commit 75b131162e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 75 additions and 96 deletions

View File

@ -17,35 +17,33 @@ import {
import { FeaturesReadModel } from '../feature-toggle/features-read-model';
import { FakeFeaturesReadModel } from '../feature-toggle/fakes/fake-features-read-model';
export const createDependentFeaturesService = (
db: Db,
config: IUnleashConfig,
): DependentFeaturesService => {
const { getLogger, eventBus } = config;
const eventStore = new EventStore(db, getLogger);
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
const eventService = new EventService(
{
eventStore,
featureTagStore,
},
config,
);
const dependentFeaturesStore = new DependentFeaturesStore(db);
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
const changeRequestAccessReadModel = createChangeRequestAccessReadModel(
db,
config,
);
const featuresReadModel = new FeaturesReadModel(db);
return new DependentFeaturesService({
dependentFeaturesStore,
dependentFeaturesReadModel,
changeRequestAccessReadModel,
featuresReadModel,
eventService,
});
};
export const createDependentFeaturesService =
(config: IUnleashConfig) => (db: Db): DependentFeaturesService => {
const { getLogger, eventBus } = config;
const eventStore = new EventStore(db, getLogger);
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
const eventService = new EventService(
{
eventStore,
featureTagStore,
},
config,
);
const dependentFeaturesStore = new DependentFeaturesStore(db);
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
const changeRequestAccessReadModel = createChangeRequestAccessReadModel(
db,
config,
);
const featuresReadModel = new FeaturesReadModel(db);
return new DependentFeaturesService({
dependentFeaturesStore,
dependentFeaturesReadModel,
changeRequestAccessReadModel,
featuresReadModel,
eventService,
});
};
export const createFakeDependentFeaturesService = (
config: IUnleashConfig,

View File

@ -20,7 +20,11 @@ import {
import { IAuthRequest } from '../../routes/unleash-types';
import { InvalidOperationError } from '../../error';
import { DependentFeaturesService } from './dependent-features-service';
import { TransactionCreator, UnleashTransaction } from '../../db/transaction';
import {
TransactionCreator,
UnleashTransaction,
WithTransactional,
} from '../../db/transaction';
interface ProjectParams {
projectId: string;
@ -44,19 +48,11 @@ const PATH_DEPENDENCY = `${PATH_FEATURE}/dependencies/:parent`;
type DependentFeaturesServices = Pick<
IUnleashServices,
| 'transactionalDependentFeaturesService'
| 'dependentFeaturesService'
| 'openApiService'
'transactionalDependentFeaturesService' | 'openApiService'
>;
export default class DependentFeaturesController extends Controller {
private transactionalDependentFeaturesService: (
db: UnleashTransaction,
) => DependentFeaturesService;
private dependentFeaturesService: DependentFeaturesService;
private readonly startTransaction: TransactionCreator<UnleashTransaction>;
private dependentFeaturesService: WithTransactional<DependentFeaturesService>;
private openApiService: OpenApiService;
@ -68,18 +64,13 @@ export default class DependentFeaturesController extends Controller {
config: IUnleashConfig,
{
transactionalDependentFeaturesService,
dependentFeaturesService,
openApiService,
}: DependentFeaturesServices,
startTransaction: TransactionCreator<UnleashTransaction>,
) {
super(config);
this.transactionalDependentFeaturesService =
transactionalDependentFeaturesService;
this.dependentFeaturesService = dependentFeaturesService;
this.dependentFeaturesService = transactionalDependentFeaturesService;
this.openApiService = openApiService;
this.flagResolver = config.flagResolver;
this.startTransaction = startTransaction;
this.logger = config.getLogger(
'/dependent-features/dependent-feature-service.ts',
);
@ -196,10 +187,8 @@ export default class DependentFeaturesController extends Controller {
const { variants, enabled, feature } = req.body;
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
await this.startTransaction(async (tx) =>
this.transactionalDependentFeaturesService(
tx,
).upsertFeatureDependency(
await this.dependentFeaturesService.transactional((service) =>
service.upsertFeatureDependency(
{ child, projectId },
{
variants,
@ -209,6 +198,7 @@ export default class DependentFeaturesController extends Controller {
req.user,
),
);
res.status(200).end();
} else {
throw new InvalidOperationError(
@ -224,13 +214,15 @@ export default class DependentFeaturesController extends Controller {
const { child, parent, projectId } = req.params;
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
await this.dependentFeaturesService.deleteFeatureDependency(
{
parent,
child,
},
projectId,
req.user,
await this.dependentFeaturesService.transactional((service) =>
service.deleteFeatureDependency(
{
parent,
child,
},
projectId,
req.user,
),
);
res.status(200).end();
} else {
@ -247,10 +239,12 @@ export default class DependentFeaturesController extends Controller {
const { child, projectId } = req.params;
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
await this.dependentFeaturesService.deleteFeaturesDependencies(
[child],
projectId,
req.user,
await this.dependentFeaturesService.transactional((service) =>
service.deleteFeaturesDependencies(
[child],
projectId,
req.user,
),
);
res.status(200).end();
} else {

View File

@ -236,10 +236,8 @@ export const deferredExportImportTogglesService = (
const segmentService = createSegmentService(db, config);
const dependentFeaturesService = createDependentFeaturesService(
db,
config,
);
const dependentFeaturesService =
createDependentFeaturesService(config)(db);
const exportImportService = new ExportImportService(
{

View File

@ -2,30 +2,29 @@ import { Logger } from '../../logger';
import { IStrategy } from '../../types/stores/strategy-store';
import { IFeatureToggleStore } from '../feature-toggle/types/feature-toggle-store-type';
import { IFeatureStrategiesStore } from '../feature-toggle/types/feature-toggle-strategies-store-type';
import {
IUnleashConfig,
IContextFieldStore,
IUnleashStores,
ISegmentStore,
IFeatureEnvironmentStore,
ITagTypeStore,
IFeatureTagStore,
FeatureToggleDTO,
IFeatureStrategy,
IFeatureStrategySegment,
IVariant,
} from '../../types';
import { ExportQuerySchema, ImportTogglesSchema } from '../../openapi';
import {
FEATURES_EXPORTED,
FEATURES_IMPORTED,
FeatureToggleDTO,
IContextFieldStore,
IFeatureEnvironmentStore,
IFeatureStrategy,
IFeatureStrategySegment,
IFeatureTagStore,
IFlagResolver,
ISegmentStore,
ITagTypeStore,
IUnleashConfig,
IUnleashServices,
IUnleashStores,
IVariant,
WithRequired,
} from '../../types';
import {
ExportQuerySchema,
ExportResultSchema,
FeatureStrategySchema,
ImportTogglesSchema,
ImportTogglesValidateSchema,
} from '../../openapi';
import User from '../../types/user';

View File

@ -119,7 +119,7 @@ export const createFeatureToggleService = (
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
const dependentFeaturesService = createDependentFeaturesService(db, config);
const dependentFeaturesService = createDependentFeaturesService(config)(db);
const featureToggleService = new FeatureToggleService(
{

View File

@ -113,14 +113,7 @@ export default class ProjectApi extends Controller {
createKnexTransactionStarter(db),
).router,
);
this.use(
'/',
new DependentFeaturesController(
config,
services,
createKnexTransactionStarter(db),
).router,
);
this.use('/', new DependentFeaturesController(config, services).router);
this.use('/', new EnvironmentsController(config, services).router);
this.use('/', new ProjectHealthReport(config, services).router);
this.use('/', new VariantsController(config, services).router);

View File

@ -267,11 +267,10 @@ export const createServices = (
privateProjectChecker,
);
const dependentFeaturesService = db
? createDependentFeaturesService(db, config)
: createFakeDependentFeaturesService(config);
const transactionalDependentFeaturesService = (txDb: Knex.Transaction) =>
createDependentFeaturesService(txDb, config);
const transactionalDependentFeaturesService = db
? withTransactional(createDependentFeaturesService(config), db)
: withFakeTransactional(createFakeDependentFeaturesService(config));
const dependentFeaturesService = transactionalDependentFeaturesService;
const featureToggleServiceV2 = new FeatureToggleService(
stores,

View File

@ -105,8 +105,6 @@ export interface IUnleashServices {
transactionalGroupService: (db: Knex.Transaction) => GroupService;
privateProjectChecker: IPrivateProjectChecker;
dependentFeaturesService: DependentFeaturesService;
transactionalDependentFeaturesService: (
db: Knex.Transaction,
) => DependentFeaturesService;
transactionalDependentFeaturesService: WithTransactional<DependentFeaturesService>;
clientFeatureToggleService: ClientFeatureToggleService;
}