1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-28 00:06:53 +01:00

feat: constraint values limit (#7498)

This commit is contained in:
Mateusz Kwasniewski 2024-07-01 13:28:30 +02:00 committed by GitHub
parent c907199d23
commit 2cfd71f34e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 81 additions and 12 deletions

View File

@ -196,6 +196,7 @@ exports[`should create default config 1`] = `
"actionSetFilterValues": 25,
"actionSetFilters": 5,
"actionSetsPerProject": 5,
"constraintValues": 250,
"environments": 50,
"featureEnvironmentStrategies": 30,
"segmentValues": 1000,

View File

@ -653,6 +653,10 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
process.env.UNLEASH_FEATURE_ENVIRONMENT_STRATEGIES_LIMIT,
30,
),
constraintValues: parseEnvVarNumber(
process.env.UNLEASH_CONSTRAINT_VALUES_LIMIT,
250,
),
environments: parseEnvVarNumber(
process.env.UNLEASH_ENVIRONMENTS_LIMIT,
50,

View File

@ -366,15 +366,14 @@ class FeatureToggleService {
}
}
async validateStrategyLimit(
featureEnv: {
projectId: string;
environment: string;
featureName: string;
},
limit: number,
) {
async validateStrategyLimit(featureEnv: {
projectId: string;
environment: string;
featureName: string;
}) {
if (!this.flagResolver.isEnabled('resourceLimits')) return;
const limit = this.resourceLimits.featureEnvironmentStrategies;
const existingCount = (
await this.featureStrategiesStore.getStrategiesForFeatureEnv(
featureEnv.projectId,
@ -387,6 +386,22 @@ class FeatureToggleService {
}
}
validateContraintValuesLimit(updatedConstrains: IConstraint[]) {
if (!this.flagResolver.isEnabled('resourceLimits')) return;
const limit = this.resourceLimits.constraintValues;
const constraintOverLimit = updatedConstrains.find(
(constraint) =>
Array.isArray(constraint.values) &&
constraint.values?.length > limit,
);
if (constraintOverLimit) {
throw new BadDataError(
`Constraint values limit of ${limit} is exceeded for ${constraintOverLimit.contextName}.`,
);
}
}
async validateStrategyType(
strategyName: string | undefined,
): Promise<void> {
@ -632,6 +647,7 @@ class FeatureToggleService {
strategyConfig.constraints &&
strategyConfig.constraints.length > 0
) {
this.validateContraintValuesLimit(strategyConfig.constraints);
strategyConfig.constraints = await this.validateConstraints(
strategyConfig.constraints,
);
@ -653,10 +669,11 @@ class FeatureToggleService {
strategyConfig.variants = fixedVariants;
}
await this.validateStrategyLimit(
{ featureName, projectId, environment },
this.resourceLimits.featureEnvironmentStrategies,
);
await this.validateStrategyLimit({
featureName,
projectId,
environment,
});
try {
const newFeatureStrategy =
@ -789,6 +806,7 @@ class FeatureToggleService {
if (existingStrategy.id === id) {
if (updates.constraints && updates.constraints.length > 0) {
this.validateContraintValuesLimit(updates.constraints);
updates.constraints = await this.validateConstraints(
updates.constraints,
);

View File

@ -1,6 +1,7 @@
import { createFakeFeatureToggleService } from '../createFeatureToggleService';
import type {
IAuditUser,
IConstraint,
IFlagResolver,
IStrategyConfig,
IUnleashConfig,
@ -43,3 +44,41 @@ test('Should not allow to exceed strategy limit', async () => {
`Strategy limit of ${LIMIT} exceeded`,
);
});
test('Should not allow to exceed constraint values limit', async () => {
const LIMIT = 3;
const { featureToggleService, featureToggleStore } =
createFakeFeatureToggleService({
getLogger,
flagResolver: alwaysOnFlagResolver,
resourceLimits: {
constraintValues: LIMIT,
},
} as unknown as IUnleashConfig);
const addStrategyWithConstraints = (constraints: IConstraint[]) =>
featureToggleService.unprotectedCreateStrategy(
{
name: 'default',
featureName: 'feature',
constraints,
} as IStrategyConfig,
{ projectId: 'default', featureName: 'feature' } as any,
{} as IAuditUser,
);
await featureToggleStore.create('default', {
name: 'feature',
createdByUserId: 1,
});
await expect(() =>
addStrategyWithConstraints([
{
contextName: 'userId',
operator: 'IN',
values: ['1', '2', '3', '4'],
},
]),
).rejects.toThrow(
`Constraint values limit of ${LIMIT} is exceeded for userId`,
);
});

View File

@ -14,6 +14,7 @@ export const resourceLimitsSchema = {
'signalEndpoints',
'signalTokensPerEndpoint',
'featureEnvironmentStrategies',
'constraintValues',
'environments',
],
additionalProperties: false,
@ -69,6 +70,12 @@ export const resourceLimitsSchema = {
description:
'The maximum number of feature environment strategies allowed.',
},
constraintValues: {
type: 'integer',
example: 250,
description:
'The maximum number of values for a single constraint.',
},
environments: {
type: 'integer',
minimum: 1,