mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	chore: revamp transactional impl (#4916)
## About the changes This transactional implementation decorates a service with a transactional method that removes the need to start transactions in the method using the service. This is a gradual rollout with a feature toggle, just because transactions are not easy.
This commit is contained in:
		
							parent
							
								
									630028acba
								
							
						
					
					
						commit
						0da48cc0d1
					
				@ -105,6 +105,7 @@ exports[`should create default config 1`] = `
 | 
			
		||||
      "proPlanAutoCharge": false,
 | 
			
		||||
      "responseTimeWithAppNameKillSwitch": false,
 | 
			
		||||
      "strictSchemaValidation": false,
 | 
			
		||||
      "transactionalDecorator": false,
 | 
			
		||||
      "variantTypeNumber": false,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
@ -144,6 +145,7 @@ exports[`should create default config 1`] = `
 | 
			
		||||
      "proPlanAutoCharge": false,
 | 
			
		||||
      "responseTimeWithAppNameKillSwitch": false,
 | 
			
		||||
      "strictSchemaValidation": false,
 | 
			
		||||
      "transactionalDecorator": false,
 | 
			
		||||
      "variantTypeNumber": false,
 | 
			
		||||
    },
 | 
			
		||||
    "externalResolver": {
 | 
			
		||||
 | 
			
		||||
@ -20,3 +20,34 @@ export const createKnexTransactionStarter = (
 | 
			
		||||
    }
 | 
			
		||||
    return transaction;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type DbServiceFactory<S> = (db: Knex) => S;
 | 
			
		||||
export type WithTransactional<S> = S & {
 | 
			
		||||
    transactional: <R>(fn: (service: S) => R) => Promise<R>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function withTransactional<S>(
 | 
			
		||||
    serviceFactory: (db: Knex) => S,
 | 
			
		||||
    db: Knex,
 | 
			
		||||
): WithTransactional<S> {
 | 
			
		||||
    const service = serviceFactory(db) as WithTransactional<S>;
 | 
			
		||||
 | 
			
		||||
    service.transactional = async <R>(fn: (service: S) => R) =>
 | 
			
		||||
        db.transaction(async (trx: Knex.Transaction) => {
 | 
			
		||||
            const transactionalService = serviceFactory(trx);
 | 
			
		||||
            return fn(transactionalService);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    return service;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Just for testing purposes */
 | 
			
		||||
export function withFakeTransactional<S>(service: S): WithTransactional<S> {
 | 
			
		||||
    const serviceWithFakeTransactional = service as WithTransactional<S>;
 | 
			
		||||
 | 
			
		||||
    serviceWithFakeTransactional.transactional = async <R>(
 | 
			
		||||
        fn: (service: S) => R,
 | 
			
		||||
    ) => fn(serviceWithFakeTransactional);
 | 
			
		||||
 | 
			
		||||
    return serviceWithFakeTransactional;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -43,6 +43,7 @@ import {
 | 
			
		||||
    createFakePrivateProjectChecker,
 | 
			
		||||
    createPrivateProjectChecker,
 | 
			
		||||
} from '../private-project/createPrivateProjectChecker';
 | 
			
		||||
import { DbServiceFactory } from 'lib/db/transaction';
 | 
			
		||||
 | 
			
		||||
export const createFakeExportImportTogglesService = (
 | 
			
		||||
    config: IUnleashConfig,
 | 
			
		||||
@ -127,109 +128,121 @@ export const createFakeExportImportTogglesService = (
 | 
			
		||||
    return exportImportService;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const deferredExportImportTogglesService = (
 | 
			
		||||
    config: IUnleashConfig,
 | 
			
		||||
): DbServiceFactory<ExportImportService> => {
 | 
			
		||||
    return (db: Db) => {
 | 
			
		||||
        const { eventBus, getLogger, flagResolver } = config;
 | 
			
		||||
        const importTogglesStore = new ImportTogglesStore(db);
 | 
			
		||||
        const featureToggleStore = new FeatureToggleStore(
 | 
			
		||||
            db,
 | 
			
		||||
            eventBus,
 | 
			
		||||
            getLogger,
 | 
			
		||||
        );
 | 
			
		||||
        const tagStore = new TagStore(db, eventBus, getLogger);
 | 
			
		||||
        const tagTypeStore = new TagTypeStore(db, eventBus, getLogger);
 | 
			
		||||
        const segmentStore = new SegmentStore(
 | 
			
		||||
            db,
 | 
			
		||||
            eventBus,
 | 
			
		||||
            getLogger,
 | 
			
		||||
            flagResolver,
 | 
			
		||||
        );
 | 
			
		||||
        const projectStore = new ProjectStore(
 | 
			
		||||
            db,
 | 
			
		||||
            eventBus,
 | 
			
		||||
            getLogger,
 | 
			
		||||
            flagResolver,
 | 
			
		||||
        );
 | 
			
		||||
        const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
 | 
			
		||||
        const strategyStore = new StrategyStore(db, getLogger);
 | 
			
		||||
        const contextFieldStore = new ContextFieldStore(
 | 
			
		||||
            db,
 | 
			
		||||
            getLogger,
 | 
			
		||||
            flagResolver,
 | 
			
		||||
        );
 | 
			
		||||
        const featureStrategiesStore = new FeatureStrategiesStore(
 | 
			
		||||
            db,
 | 
			
		||||
            eventBus,
 | 
			
		||||
            getLogger,
 | 
			
		||||
            flagResolver,
 | 
			
		||||
        );
 | 
			
		||||
        const featureEnvironmentStore = new FeatureEnvironmentStore(
 | 
			
		||||
            db,
 | 
			
		||||
            eventBus,
 | 
			
		||||
            getLogger,
 | 
			
		||||
        );
 | 
			
		||||
        const eventStore = new EventStore(db, getLogger);
 | 
			
		||||
        const accessService = createAccessService(db, config);
 | 
			
		||||
        const featureToggleService = createFeatureToggleService(db, config);
 | 
			
		||||
        const privateProjectChecker = createPrivateProjectChecker(db, config);
 | 
			
		||||
 | 
			
		||||
        const eventService = new EventService(
 | 
			
		||||
            {
 | 
			
		||||
                eventStore,
 | 
			
		||||
                featureTagStore,
 | 
			
		||||
            },
 | 
			
		||||
            config,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const featureTagService = new FeatureTagService(
 | 
			
		||||
            {
 | 
			
		||||
                tagStore,
 | 
			
		||||
                featureTagStore,
 | 
			
		||||
                featureToggleStore,
 | 
			
		||||
            },
 | 
			
		||||
            { getLogger },
 | 
			
		||||
            eventService,
 | 
			
		||||
        );
 | 
			
		||||
        const contextService = new ContextService(
 | 
			
		||||
            {
 | 
			
		||||
                projectStore,
 | 
			
		||||
                contextFieldStore,
 | 
			
		||||
                featureStrategiesStore,
 | 
			
		||||
            },
 | 
			
		||||
            { getLogger, flagResolver },
 | 
			
		||||
            eventService,
 | 
			
		||||
            privateProjectChecker,
 | 
			
		||||
        );
 | 
			
		||||
        const strategyService = new StrategyService(
 | 
			
		||||
            { strategyStore },
 | 
			
		||||
            { getLogger },
 | 
			
		||||
            eventService,
 | 
			
		||||
        );
 | 
			
		||||
        const tagTypeService = new TagTypeService(
 | 
			
		||||
            { tagTypeStore },
 | 
			
		||||
            { getLogger },
 | 
			
		||||
            eventService,
 | 
			
		||||
        );
 | 
			
		||||
        const exportImportService = new ExportImportService(
 | 
			
		||||
            {
 | 
			
		||||
                importTogglesStore,
 | 
			
		||||
                featureStrategiesStore,
 | 
			
		||||
                contextFieldStore,
 | 
			
		||||
                featureToggleStore,
 | 
			
		||||
                featureTagStore,
 | 
			
		||||
                segmentStore,
 | 
			
		||||
                tagTypeStore,
 | 
			
		||||
                featureEnvironmentStore,
 | 
			
		||||
            },
 | 
			
		||||
            config,
 | 
			
		||||
            {
 | 
			
		||||
                featureToggleService,
 | 
			
		||||
                featureTagService,
 | 
			
		||||
                accessService,
 | 
			
		||||
                eventService,
 | 
			
		||||
                contextService,
 | 
			
		||||
                strategyService,
 | 
			
		||||
                tagTypeService,
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return exportImportService;
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
export const createExportImportTogglesService = (
 | 
			
		||||
    db: Db,
 | 
			
		||||
    config: IUnleashConfig,
 | 
			
		||||
): ExportImportService => {
 | 
			
		||||
    const { eventBus, getLogger, flagResolver } = config;
 | 
			
		||||
    const importTogglesStore = new ImportTogglesStore(db);
 | 
			
		||||
    const featureToggleStore = new FeatureToggleStore(db, eventBus, getLogger);
 | 
			
		||||
    const tagStore = new TagStore(db, eventBus, getLogger);
 | 
			
		||||
    const tagTypeStore = new TagTypeStore(db, eventBus, getLogger);
 | 
			
		||||
    const segmentStore = new SegmentStore(
 | 
			
		||||
        db,
 | 
			
		||||
        eventBus,
 | 
			
		||||
        getLogger,
 | 
			
		||||
        flagResolver,
 | 
			
		||||
    );
 | 
			
		||||
    const projectStore = new ProjectStore(
 | 
			
		||||
        db,
 | 
			
		||||
        eventBus,
 | 
			
		||||
        getLogger,
 | 
			
		||||
        flagResolver,
 | 
			
		||||
    );
 | 
			
		||||
    const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
 | 
			
		||||
    const strategyStore = new StrategyStore(db, getLogger);
 | 
			
		||||
    const contextFieldStore = new ContextFieldStore(
 | 
			
		||||
        db,
 | 
			
		||||
        getLogger,
 | 
			
		||||
        flagResolver,
 | 
			
		||||
    );
 | 
			
		||||
    const featureStrategiesStore = new FeatureStrategiesStore(
 | 
			
		||||
        db,
 | 
			
		||||
        eventBus,
 | 
			
		||||
        getLogger,
 | 
			
		||||
        flagResolver,
 | 
			
		||||
    );
 | 
			
		||||
    const featureEnvironmentStore = new FeatureEnvironmentStore(
 | 
			
		||||
        db,
 | 
			
		||||
        eventBus,
 | 
			
		||||
        getLogger,
 | 
			
		||||
    );
 | 
			
		||||
    const eventStore = new EventStore(db, getLogger);
 | 
			
		||||
    const accessService = createAccessService(db, config);
 | 
			
		||||
    const featureToggleService = createFeatureToggleService(db, config);
 | 
			
		||||
    const privateProjectChecker = createPrivateProjectChecker(db, config);
 | 
			
		||||
 | 
			
		||||
    const eventService = new EventService(
 | 
			
		||||
        {
 | 
			
		||||
            eventStore,
 | 
			
		||||
            featureTagStore,
 | 
			
		||||
        },
 | 
			
		||||
        config,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const featureTagService = new FeatureTagService(
 | 
			
		||||
        {
 | 
			
		||||
            tagStore,
 | 
			
		||||
            featureTagStore,
 | 
			
		||||
            featureToggleStore,
 | 
			
		||||
        },
 | 
			
		||||
        { getLogger },
 | 
			
		||||
        eventService,
 | 
			
		||||
    );
 | 
			
		||||
    const contextService = new ContextService(
 | 
			
		||||
        {
 | 
			
		||||
            projectStore,
 | 
			
		||||
            contextFieldStore,
 | 
			
		||||
            featureStrategiesStore,
 | 
			
		||||
        },
 | 
			
		||||
        { getLogger, flagResolver },
 | 
			
		||||
        eventService,
 | 
			
		||||
        privateProjectChecker,
 | 
			
		||||
    );
 | 
			
		||||
    const strategyService = new StrategyService(
 | 
			
		||||
        { strategyStore },
 | 
			
		||||
        { getLogger },
 | 
			
		||||
        eventService,
 | 
			
		||||
    );
 | 
			
		||||
    const tagTypeService = new TagTypeService(
 | 
			
		||||
        { tagTypeStore },
 | 
			
		||||
        { getLogger },
 | 
			
		||||
        eventService,
 | 
			
		||||
    );
 | 
			
		||||
    const exportImportService = new ExportImportService(
 | 
			
		||||
        {
 | 
			
		||||
            importTogglesStore,
 | 
			
		||||
            featureStrategiesStore,
 | 
			
		||||
            contextFieldStore,
 | 
			
		||||
            featureToggleStore,
 | 
			
		||||
            featureTagStore,
 | 
			
		||||
            segmentStore,
 | 
			
		||||
            tagTypeStore,
 | 
			
		||||
            featureEnvironmentStore,
 | 
			
		||||
        },
 | 
			
		||||
        config,
 | 
			
		||||
        {
 | 
			
		||||
            featureToggleService,
 | 
			
		||||
            featureTagService,
 | 
			
		||||
            accessService,
 | 
			
		||||
            eventService,
 | 
			
		||||
            contextService,
 | 
			
		||||
            strategyService,
 | 
			
		||||
            tagTypeService,
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return exportImportService;
 | 
			
		||||
    const unboundService = deferredExportImportTogglesService(config);
 | 
			
		||||
    return unboundService(db);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,11 @@ import Controller from '../../routes/controller';
 | 
			
		||||
import { Logger } from '../../logger';
 | 
			
		||||
import ExportImportService from './export-import-service';
 | 
			
		||||
import { OpenApiService } from '../../services';
 | 
			
		||||
import { TransactionCreator, UnleashTransaction } from '../../db/transaction';
 | 
			
		||||
import {
 | 
			
		||||
    TransactionCreator,
 | 
			
		||||
    UnleashTransaction,
 | 
			
		||||
    WithTransactional,
 | 
			
		||||
} from '../../db/transaction';
 | 
			
		||||
import {
 | 
			
		||||
    IUnleashConfig,
 | 
			
		||||
    IUnleashServices,
 | 
			
		||||
@ -28,14 +32,19 @@ import ApiUser from '../../types/api-user';
 | 
			
		||||
class ExportImportController extends Controller {
 | 
			
		||||
    private logger: Logger;
 | 
			
		||||
 | 
			
		||||
    /** @deprecated gradually rolling out exportImportV2 */
 | 
			
		||||
    private exportImportService: ExportImportService;
 | 
			
		||||
 | 
			
		||||
    /** @deprecated gradually rolling out exportImportV2 */
 | 
			
		||||
    private transactionalExportImportService: (
 | 
			
		||||
        db: UnleashTransaction,
 | 
			
		||||
    ) => ExportImportService;
 | 
			
		||||
 | 
			
		||||
    private exportImportServiceV2: WithTransactional<ExportImportService>;
 | 
			
		||||
 | 
			
		||||
    private openApiService: OpenApiService;
 | 
			
		||||
 | 
			
		||||
    /** @deprecated gradually rolling out exportImportV2 */
 | 
			
		||||
    private readonly startTransaction: TransactionCreator<UnleashTransaction>;
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
@ -43,10 +52,12 @@ class ExportImportController extends Controller {
 | 
			
		||||
        {
 | 
			
		||||
            exportImportService,
 | 
			
		||||
            transactionalExportImportService,
 | 
			
		||||
            exportImportServiceV2,
 | 
			
		||||
            openApiService,
 | 
			
		||||
        }: Pick<
 | 
			
		||||
            IUnleashServices,
 | 
			
		||||
            | 'exportImportService'
 | 
			
		||||
            | 'exportImportServiceV2'
 | 
			
		||||
            | 'openApiService'
 | 
			
		||||
            | 'transactionalExportImportService'
 | 
			
		||||
        >,
 | 
			
		||||
@ -57,6 +68,7 @@ class ExportImportController extends Controller {
 | 
			
		||||
        this.exportImportService = exportImportService;
 | 
			
		||||
        this.transactionalExportImportService =
 | 
			
		||||
            transactionalExportImportService;
 | 
			
		||||
        this.exportImportServiceV2 = exportImportServiceV2;
 | 
			
		||||
        this.startTransaction = startTransaction;
 | 
			
		||||
        this.openApiService = openApiService;
 | 
			
		||||
        this.route({
 | 
			
		||||
@ -128,7 +140,13 @@ class ExportImportController extends Controller {
 | 
			
		||||
        this.verifyExportImportEnabled();
 | 
			
		||||
        const query = req.body;
 | 
			
		||||
        const userName = extractUsername(req);
 | 
			
		||||
        const data = await this.exportImportService.export(query, userName);
 | 
			
		||||
 | 
			
		||||
        const useTransactionalDecorator = this.config.flagResolver.isEnabled(
 | 
			
		||||
            'transactionalDecorator',
 | 
			
		||||
        );
 | 
			
		||||
        const data = useTransactionalDecorator
 | 
			
		||||
            ? await this.exportImportServiceV2.export(query, userName)
 | 
			
		||||
            : await this.exportImportService.export(query, userName);
 | 
			
		||||
 | 
			
		||||
        this.openApiService.respondWithValidation(
 | 
			
		||||
            200,
 | 
			
		||||
@ -145,9 +163,17 @@ class ExportImportController extends Controller {
 | 
			
		||||
        this.verifyExportImportEnabled();
 | 
			
		||||
        const dto = req.body;
 | 
			
		||||
        const { user } = req;
 | 
			
		||||
        const validation = await this.startTransaction(async (tx) =>
 | 
			
		||||
            this.transactionalExportImportService(tx).validate(dto, user),
 | 
			
		||||
 | 
			
		||||
        const useTransactionalDecorator = this.config.flagResolver.isEnabled(
 | 
			
		||||
            'transactionalDecorator',
 | 
			
		||||
        );
 | 
			
		||||
        const validation = useTransactionalDecorator
 | 
			
		||||
            ? await this.exportImportServiceV2.transactional((service) =>
 | 
			
		||||
                  service.validate(dto, user),
 | 
			
		||||
              )
 | 
			
		||||
            : await this.startTransaction(async (tx) =>
 | 
			
		||||
                  this.transactionalExportImportService(tx).validate(dto, user),
 | 
			
		||||
              );
 | 
			
		||||
 | 
			
		||||
        this.openApiService.respondWithValidation(
 | 
			
		||||
            200,
 | 
			
		||||
@ -172,10 +198,20 @@ class ExportImportController extends Controller {
 | 
			
		||||
 | 
			
		||||
        const dto = req.body;
 | 
			
		||||
 | 
			
		||||
        await this.startTransaction(async (tx) =>
 | 
			
		||||
            this.transactionalExportImportService(tx).import(dto, user),
 | 
			
		||||
        const useTransactionalDecorator = this.config.flagResolver.isEnabled(
 | 
			
		||||
            'transactionalDecorator',
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (useTransactionalDecorator) {
 | 
			
		||||
            await this.exportImportServiceV2.transactional((service) =>
 | 
			
		||||
                service.import(dto, user),
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            await this.startTransaction(async (tx) =>
 | 
			
		||||
                this.transactionalExportImportService(tx).import(dto, user),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        res.status(200).end();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -50,8 +50,10 @@ import { Knex } from 'knex';
 | 
			
		||||
import {
 | 
			
		||||
    createExportImportTogglesService,
 | 
			
		||||
    createFakeExportImportTogglesService,
 | 
			
		||||
    deferredExportImportTogglesService,
 | 
			
		||||
} from '../features/export-import-toggles/createExportImportService';
 | 
			
		||||
import { Db } from '../db/db';
 | 
			
		||||
import { withFakeTransactional, withTransactional } from '../db/transaction';
 | 
			
		||||
import {
 | 
			
		||||
    createChangeRequestAccessReadModel,
 | 
			
		||||
    createFakeChangeRequestAccessService,
 | 
			
		||||
@ -274,10 +276,12 @@ export const createServices = (
 | 
			
		||||
        projectService,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // TODO: this is a temporary seam to enable packaging by feature
 | 
			
		||||
    const exportImportService = db
 | 
			
		||||
        ? createExportImportTogglesService(db, config)
 | 
			
		||||
        : createFakeExportImportTogglesService(config);
 | 
			
		||||
    const exportImportServiceV2 = db
 | 
			
		||||
        ? withTransactional(deferredExportImportTogglesService(config), db)
 | 
			
		||||
        : withFakeTransactional(createFakeExportImportTogglesService(config));
 | 
			
		||||
    const transactionalExportImportService = (txDb: Knex.Transaction) =>
 | 
			
		||||
        createExportImportTogglesService(txDb, config);
 | 
			
		||||
    const transactionalFeatureToggleService = (txDb: Knex.Transaction) =>
 | 
			
		||||
@ -380,6 +384,7 @@ export const createServices = (
 | 
			
		||||
        maintenanceService,
 | 
			
		||||
        exportImportService,
 | 
			
		||||
        transactionalExportImportService,
 | 
			
		||||
        exportImportServiceV2,
 | 
			
		||||
        schedulerService,
 | 
			
		||||
        configurationRevisionService,
 | 
			
		||||
        transactionalFeatureToggleService,
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,8 @@ export type IFlagKey =
 | 
			
		||||
    | 'privateProjects'
 | 
			
		||||
    | 'dependentFeatures'
 | 
			
		||||
    | 'datadogJsonTemplate'
 | 
			
		||||
    | 'disableMetrics';
 | 
			
		||||
    | 'disableMetrics'
 | 
			
		||||
    | 'transactionalDecorator';
 | 
			
		||||
 | 
			
		||||
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
 | 
			
		||||
 | 
			
		||||
@ -147,6 +148,10 @@ const flags: IFlags = {
 | 
			
		||||
        process.env.UNLEASH_EXPERIMENTAL_DISABLE_METRICS,
 | 
			
		||||
        false,
 | 
			
		||||
    ),
 | 
			
		||||
    transactionalDecorator: parseEnvVarBoolean(
 | 
			
		||||
        process.env.UNLEASH_EXPERIMENTAL_TRANSACTIONAL_DECORATOR,
 | 
			
		||||
        false,
 | 
			
		||||
    ),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const defaultExperimentalOptions: IExperimentalOptions = {
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,7 @@ import ConfigurationRevisionService from '../features/feature-toggle/configurati
 | 
			
		||||
import EventAnnouncerService from 'lib/services/event-announcer-service';
 | 
			
		||||
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
 | 
			
		||||
import { DependentFeaturesService } from '../features/dependent-features/dependent-features-service';
 | 
			
		||||
import { WithTransactional } from 'lib/db/transaction';
 | 
			
		||||
 | 
			
		||||
export interface IUnleashServices {
 | 
			
		||||
    accessService: AccessService;
 | 
			
		||||
@ -88,10 +89,13 @@ export interface IUnleashServices {
 | 
			
		||||
    instanceStatsService: InstanceStatsService;
 | 
			
		||||
    favoritesService: FavoritesService;
 | 
			
		||||
    maintenanceService: MaintenanceService;
 | 
			
		||||
    /** @deprecated prefer exportImportServiceV2, we're doing a gradual rollout */
 | 
			
		||||
    exportImportService: ExportImportService;
 | 
			
		||||
    exportImportServiceV2: WithTransactional<ExportImportService>;
 | 
			
		||||
    configurationRevisionService: ConfigurationRevisionService;
 | 
			
		||||
    schedulerService: SchedulerService;
 | 
			
		||||
    eventAnnouncerService: EventAnnouncerService;
 | 
			
		||||
    /** @deprecated prefer exportImportServiceV2, we're doing a gradual rollout */
 | 
			
		||||
    transactionalExportImportService: (
 | 
			
		||||
        db: Knex.Transaction,
 | 
			
		||||
    ) => ExportImportService;
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,7 @@ process.nextTick(async () => {
 | 
			
		||||
                        accessOverview: true,
 | 
			
		||||
                        datadogJsonTemplate: true,
 | 
			
		||||
                        dependentFeatures: true,
 | 
			
		||||
                        transactionalDecorator: true,
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                authentication: {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user