1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-13 13:48:59 +02:00

Fix: only flexibleRollout strategy should use defaults

This commit is contained in:
Gastón Fournier 2025-07-30 12:49:34 +02:00
parent d56e88eef2
commit 8712bd17e9
No known key found for this signature in database
GPG Key ID: AF45428626E17A8E
4 changed files with 54 additions and 54 deletions

View File

@ -54,9 +54,7 @@ exports[`should match snapshot from /api/client/features 1`] = `
},
],
"name": "default",
"parameters": {
"stickiness": "default",
},
"parameters": {},
"variants": [],
},
],

View File

@ -70,9 +70,7 @@ const getApiClientResponse = (project = 'default') => [
values: ['123'],
},
],
parameters: {
stickiness: 'default',
},
parameters: {},
variants: [],
},
],

View File

@ -117,7 +117,7 @@ import { sortStrategies } from '../../util/sortStrategies.js';
import type { ResourceLimitsSchema } from '../../openapi/index.js';
import type FeatureLinkService from '../feature-links/feature-link-service.js';
import type { IFeatureLink } from '../feature-links/feature-links-read-model-type.js';
import merge from 'deepmerge';
interface IFeatureContext {
featureName: string;
projectId: string;
@ -126,6 +126,9 @@ interface IFeatureContext {
interface IFeatureStrategyContext extends IFeatureContext {
environment: string;
}
function mergeAll<T>(objects: Partial<T>[]): T {
return merge.all<T>(objects.filter((i) => i));
}
export interface IGetFeatureParams {
featureName: string;
@ -670,7 +673,48 @@ export class FeatureToggleService {
);
}
async standardizeStrategyConfig(
private async defaultParameters(
projectId: string,
strategyName: string,
featureName: string,
params: IFeatureStrategy['parameters'] | undefined,
) {
if (strategyName === 'flexibleRollout') {
if (params?.stickiness === '') {
// If stickiness is an empty string, we remove it to use the default stickiness.
delete params?.stickiness;
}
return {
rollout: '100',
stickiness:
params?.stickiness ??
(await this.featureStrategiesStore.getDefaultStickiness(
projectId,
)),
groupId: featureName,
};
} else {
/// We don't really have good defaults for the other kinds of known strategies, so return an empty map.
return {};
}
}
private async parametersWithDefaults(
projectId: string,
strategyName: string,
featureName: string,
params: IFeatureStrategy['parameters'] | undefined,
) {
return mergeAll([
await this.defaultParameters(
projectId,
strategyName,
featureName,
params,
),
params ?? {},
]);
}
private async standardizeStrategyConfig(
projectId: string,
strategyConfig: Unsaved<IStrategyConfig>,
existing?: IFeatureStrategy,
@ -695,18 +739,12 @@ export class FeatureToggleService {
constraints = await this.validateConstraints(constraints);
}
if (
parameters &&
(!('stickiness' in parameters) ||
('stickiness' in parameters && parameters.stickiness === ''))
) {
parameters.stickiness =
existing?.parameters?.stickiness ||
(await this.featureStrategiesStore.getDefaultStickiness(
projectId,
));
}
parameters = await this.parametersWithDefaults(
projectId,
name,
strategyConfig.featureName!,
strategyConfig.parameters,
);
if (variants && variants.length > 0) {
await variantsArraySchema.validateAsync(variants);
const fixedVariants = this.fixVariantWeights(variants);

View File

@ -28,7 +28,6 @@ import {
import type { IFeatureProjectUserParams } from './feature-toggle-controller.js';
import type { Db } from '../../db/db.js';
import { isAfter } from 'date-fns';
import merge from 'deepmerge';
import Raw = Knex.Raw;
import type { ITag } from '../../tags/index.js';
@ -157,32 +156,6 @@ function mapStrategyUpdate(
return update;
}
function mergeAll<T>(objects: Partial<T>[]): T {
return merge.all<T>(objects.filter((i) => i));
}
const defaultParameters = (
params: PartialSome<IFeatureStrategy, 'id' | 'createdAt'>,
stickiness: string,
) => {
if (params.strategyName === 'flexibleRollout') {
return {
rollout: '100',
stickiness,
groupId: params.featureName,
};
} else {
/// We don't really have good defaults for the other kinds of known strategies, so return an empty map.
return {};
}
};
const parametersWithDefaults = (
params: PartialSome<IFeatureStrategy, 'id' | 'createdAt'>,
stickiness: string,
) => {
return mergeAll([defaultParameters(params, stickiness), params.parameters]);
};
class FeatureStrategiesStore implements IFeatureStrategiesStore {
private db: Db;
@ -264,13 +237,6 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
strategyConfig.featureName,
strategyConfig.environment,
));
const stickiness =
strategyConfig.parameters?.stickiness ??
(await this.getDefaultStickiness(strategyConfig.projectId));
strategyConfig.parameters = parametersWithDefaults(
strategyConfig,
stickiness,
);
const strategyRow = mapInput({
id: uuidv4(),
...strategyConfig,