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:
parent
4dd01c1765
commit
75b131162e
@ -17,35 +17,33 @@ import {
|
|||||||
import { FeaturesReadModel } from '../feature-toggle/features-read-model';
|
import { FeaturesReadModel } from '../feature-toggle/features-read-model';
|
||||||
import { FakeFeaturesReadModel } from '../feature-toggle/fakes/fake-features-read-model';
|
import { FakeFeaturesReadModel } from '../feature-toggle/fakes/fake-features-read-model';
|
||||||
|
|
||||||
export const createDependentFeaturesService = (
|
export const createDependentFeaturesService =
|
||||||
db: Db,
|
(config: IUnleashConfig) => (db: Db): DependentFeaturesService => {
|
||||||
config: IUnleashConfig,
|
const { getLogger, eventBus } = config;
|
||||||
): DependentFeaturesService => {
|
const eventStore = new EventStore(db, getLogger);
|
||||||
const { getLogger, eventBus } = config;
|
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
|
||||||
const eventStore = new EventStore(db, getLogger);
|
const eventService = new EventService(
|
||||||
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
|
{
|
||||||
const eventService = new EventService(
|
eventStore,
|
||||||
{
|
featureTagStore,
|
||||||
eventStore,
|
},
|
||||||
featureTagStore,
|
config,
|
||||||
},
|
);
|
||||||
config,
|
const dependentFeaturesStore = new DependentFeaturesStore(db);
|
||||||
);
|
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
|
||||||
const dependentFeaturesStore = new DependentFeaturesStore(db);
|
const changeRequestAccessReadModel = createChangeRequestAccessReadModel(
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
|
db,
|
||||||
const changeRequestAccessReadModel = createChangeRequestAccessReadModel(
|
config,
|
||||||
db,
|
);
|
||||||
config,
|
const featuresReadModel = new FeaturesReadModel(db);
|
||||||
);
|
return new DependentFeaturesService({
|
||||||
const featuresReadModel = new FeaturesReadModel(db);
|
dependentFeaturesStore,
|
||||||
return new DependentFeaturesService({
|
dependentFeaturesReadModel,
|
||||||
dependentFeaturesStore,
|
changeRequestAccessReadModel,
|
||||||
dependentFeaturesReadModel,
|
featuresReadModel,
|
||||||
changeRequestAccessReadModel,
|
eventService,
|
||||||
featuresReadModel,
|
});
|
||||||
eventService,
|
};
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createFakeDependentFeaturesService = (
|
export const createFakeDependentFeaturesService = (
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
|
@ -20,7 +20,11 @@ import {
|
|||||||
import { IAuthRequest } from '../../routes/unleash-types';
|
import { IAuthRequest } from '../../routes/unleash-types';
|
||||||
import { InvalidOperationError } from '../../error';
|
import { InvalidOperationError } from '../../error';
|
||||||
import { DependentFeaturesService } from './dependent-features-service';
|
import { DependentFeaturesService } from './dependent-features-service';
|
||||||
import { TransactionCreator, UnleashTransaction } from '../../db/transaction';
|
import {
|
||||||
|
TransactionCreator,
|
||||||
|
UnleashTransaction,
|
||||||
|
WithTransactional,
|
||||||
|
} from '../../db/transaction';
|
||||||
|
|
||||||
interface ProjectParams {
|
interface ProjectParams {
|
||||||
projectId: string;
|
projectId: string;
|
||||||
@ -44,19 +48,11 @@ const PATH_DEPENDENCY = `${PATH_FEATURE}/dependencies/:parent`;
|
|||||||
|
|
||||||
type DependentFeaturesServices = Pick<
|
type DependentFeaturesServices = Pick<
|
||||||
IUnleashServices,
|
IUnleashServices,
|
||||||
| 'transactionalDependentFeaturesService'
|
'transactionalDependentFeaturesService' | 'openApiService'
|
||||||
| 'dependentFeaturesService'
|
|
||||||
| 'openApiService'
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export default class DependentFeaturesController extends Controller {
|
export default class DependentFeaturesController extends Controller {
|
||||||
private transactionalDependentFeaturesService: (
|
private dependentFeaturesService: WithTransactional<DependentFeaturesService>;
|
||||||
db: UnleashTransaction,
|
|
||||||
) => DependentFeaturesService;
|
|
||||||
|
|
||||||
private dependentFeaturesService: DependentFeaturesService;
|
|
||||||
|
|
||||||
private readonly startTransaction: TransactionCreator<UnleashTransaction>;
|
|
||||||
|
|
||||||
private openApiService: OpenApiService;
|
private openApiService: OpenApiService;
|
||||||
|
|
||||||
@ -68,18 +64,13 @@ export default class DependentFeaturesController extends Controller {
|
|||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
{
|
{
|
||||||
transactionalDependentFeaturesService,
|
transactionalDependentFeaturesService,
|
||||||
dependentFeaturesService,
|
|
||||||
openApiService,
|
openApiService,
|
||||||
}: DependentFeaturesServices,
|
}: DependentFeaturesServices,
|
||||||
startTransaction: TransactionCreator<UnleashTransaction>,
|
|
||||||
) {
|
) {
|
||||||
super(config);
|
super(config);
|
||||||
this.transactionalDependentFeaturesService =
|
this.dependentFeaturesService = transactionalDependentFeaturesService;
|
||||||
transactionalDependentFeaturesService;
|
|
||||||
this.dependentFeaturesService = dependentFeaturesService;
|
|
||||||
this.openApiService = openApiService;
|
this.openApiService = openApiService;
|
||||||
this.flagResolver = config.flagResolver;
|
this.flagResolver = config.flagResolver;
|
||||||
this.startTransaction = startTransaction;
|
|
||||||
this.logger = config.getLogger(
|
this.logger = config.getLogger(
|
||||||
'/dependent-features/dependent-feature-service.ts',
|
'/dependent-features/dependent-feature-service.ts',
|
||||||
);
|
);
|
||||||
@ -196,10 +187,8 @@ export default class DependentFeaturesController extends Controller {
|
|||||||
const { variants, enabled, feature } = req.body;
|
const { variants, enabled, feature } = req.body;
|
||||||
|
|
||||||
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
|
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
|
||||||
await this.startTransaction(async (tx) =>
|
await this.dependentFeaturesService.transactional((service) =>
|
||||||
this.transactionalDependentFeaturesService(
|
service.upsertFeatureDependency(
|
||||||
tx,
|
|
||||||
).upsertFeatureDependency(
|
|
||||||
{ child, projectId },
|
{ child, projectId },
|
||||||
{
|
{
|
||||||
variants,
|
variants,
|
||||||
@ -209,6 +198,7 @@ export default class DependentFeaturesController extends Controller {
|
|||||||
req.user,
|
req.user,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidOperationError(
|
throw new InvalidOperationError(
|
||||||
@ -224,13 +214,15 @@ export default class DependentFeaturesController extends Controller {
|
|||||||
const { child, parent, projectId } = req.params;
|
const { child, parent, projectId } = req.params;
|
||||||
|
|
||||||
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
|
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
|
||||||
await this.dependentFeaturesService.deleteFeatureDependency(
|
await this.dependentFeaturesService.transactional((service) =>
|
||||||
{
|
service.deleteFeatureDependency(
|
||||||
parent,
|
{
|
||||||
child,
|
parent,
|
||||||
},
|
child,
|
||||||
projectId,
|
},
|
||||||
req.user,
|
projectId,
|
||||||
|
req.user,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
} else {
|
} else {
|
||||||
@ -247,10 +239,12 @@ export default class DependentFeaturesController extends Controller {
|
|||||||
const { child, projectId } = req.params;
|
const { child, projectId } = req.params;
|
||||||
|
|
||||||
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
|
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
|
||||||
await this.dependentFeaturesService.deleteFeaturesDependencies(
|
await this.dependentFeaturesService.transactional((service) =>
|
||||||
[child],
|
service.deleteFeaturesDependencies(
|
||||||
projectId,
|
[child],
|
||||||
req.user,
|
projectId,
|
||||||
|
req.user,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
} else {
|
} else {
|
||||||
|
@ -236,10 +236,8 @@ export const deferredExportImportTogglesService = (
|
|||||||
|
|
||||||
const segmentService = createSegmentService(db, config);
|
const segmentService = createSegmentService(db, config);
|
||||||
|
|
||||||
const dependentFeaturesService = createDependentFeaturesService(
|
const dependentFeaturesService =
|
||||||
db,
|
createDependentFeaturesService(config)(db);
|
||||||
config,
|
|
||||||
);
|
|
||||||
|
|
||||||
const exportImportService = new ExportImportService(
|
const exportImportService = new ExportImportService(
|
||||||
{
|
{
|
||||||
|
@ -2,30 +2,29 @@ import { Logger } from '../../logger';
|
|||||||
import { IStrategy } from '../../types/stores/strategy-store';
|
import { IStrategy } from '../../types/stores/strategy-store';
|
||||||
import { IFeatureToggleStore } from '../feature-toggle/types/feature-toggle-store-type';
|
import { IFeatureToggleStore } from '../feature-toggle/types/feature-toggle-store-type';
|
||||||
import { IFeatureStrategiesStore } from '../feature-toggle/types/feature-toggle-strategies-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 {
|
import {
|
||||||
FEATURES_EXPORTED,
|
FEATURES_EXPORTED,
|
||||||
FEATURES_IMPORTED,
|
FEATURES_IMPORTED,
|
||||||
|
FeatureToggleDTO,
|
||||||
|
IContextFieldStore,
|
||||||
|
IFeatureEnvironmentStore,
|
||||||
|
IFeatureStrategy,
|
||||||
|
IFeatureStrategySegment,
|
||||||
|
IFeatureTagStore,
|
||||||
IFlagResolver,
|
IFlagResolver,
|
||||||
|
ISegmentStore,
|
||||||
|
ITagTypeStore,
|
||||||
|
IUnleashConfig,
|
||||||
IUnleashServices,
|
IUnleashServices,
|
||||||
|
IUnleashStores,
|
||||||
|
IVariant,
|
||||||
WithRequired,
|
WithRequired,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
import {
|
import {
|
||||||
|
ExportQuerySchema,
|
||||||
ExportResultSchema,
|
ExportResultSchema,
|
||||||
FeatureStrategySchema,
|
FeatureStrategySchema,
|
||||||
|
ImportTogglesSchema,
|
||||||
ImportTogglesValidateSchema,
|
ImportTogglesValidateSchema,
|
||||||
} from '../../openapi';
|
} from '../../openapi';
|
||||||
import User from '../../types/user';
|
import User from '../../types/user';
|
||||||
|
@ -119,7 +119,7 @@ export const createFeatureToggleService = (
|
|||||||
|
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
|
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
|
||||||
|
|
||||||
const dependentFeaturesService = createDependentFeaturesService(db, config);
|
const dependentFeaturesService = createDependentFeaturesService(config)(db);
|
||||||
|
|
||||||
const featureToggleService = new FeatureToggleService(
|
const featureToggleService = new FeatureToggleService(
|
||||||
{
|
{
|
||||||
|
@ -113,14 +113,7 @@ export default class ProjectApi extends Controller {
|
|||||||
createKnexTransactionStarter(db),
|
createKnexTransactionStarter(db),
|
||||||
).router,
|
).router,
|
||||||
);
|
);
|
||||||
this.use(
|
this.use('/', new DependentFeaturesController(config, services).router);
|
||||||
'/',
|
|
||||||
new DependentFeaturesController(
|
|
||||||
config,
|
|
||||||
services,
|
|
||||||
createKnexTransactionStarter(db),
|
|
||||||
).router,
|
|
||||||
);
|
|
||||||
this.use('/', new EnvironmentsController(config, services).router);
|
this.use('/', new EnvironmentsController(config, services).router);
|
||||||
this.use('/', new ProjectHealthReport(config, services).router);
|
this.use('/', new ProjectHealthReport(config, services).router);
|
||||||
this.use('/', new VariantsController(config, services).router);
|
this.use('/', new VariantsController(config, services).router);
|
||||||
|
@ -267,11 +267,10 @@ export const createServices = (
|
|||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
);
|
);
|
||||||
|
|
||||||
const dependentFeaturesService = db
|
const transactionalDependentFeaturesService = db
|
||||||
? createDependentFeaturesService(db, config)
|
? withTransactional(createDependentFeaturesService(config), db)
|
||||||
: createFakeDependentFeaturesService(config);
|
: withFakeTransactional(createFakeDependentFeaturesService(config));
|
||||||
const transactionalDependentFeaturesService = (txDb: Knex.Transaction) =>
|
const dependentFeaturesService = transactionalDependentFeaturesService;
|
||||||
createDependentFeaturesService(txDb, config);
|
|
||||||
|
|
||||||
const featureToggleServiceV2 = new FeatureToggleService(
|
const featureToggleServiceV2 = new FeatureToggleService(
|
||||||
stores,
|
stores,
|
||||||
|
@ -105,8 +105,6 @@ export interface IUnleashServices {
|
|||||||
transactionalGroupService: (db: Knex.Transaction) => GroupService;
|
transactionalGroupService: (db: Knex.Transaction) => GroupService;
|
||||||
privateProjectChecker: IPrivateProjectChecker;
|
privateProjectChecker: IPrivateProjectChecker;
|
||||||
dependentFeaturesService: DependentFeaturesService;
|
dependentFeaturesService: DependentFeaturesService;
|
||||||
transactionalDependentFeaturesService: (
|
transactionalDependentFeaturesService: WithTransactional<DependentFeaturesService>;
|
||||||
db: Knex.Transaction,
|
|
||||||
) => DependentFeaturesService;
|
|
||||||
clientFeatureToggleService: ClientFeatureToggleService;
|
clientFeatureToggleService: ClientFeatureToggleService;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user