1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-31 00:16:47 +01:00

feat: allow stickiness on context-fields (#713)

* feat: allow stickiness on context-fields

* chore: docs for this feature

* fix: write a small e2e test

* fix: add stickiness to variants
This commit is contained in:
Ivar Conradi Østhus 2021-02-11 17:59:16 +01:00 committed by GitHub
parent e65a55cd19
commit 4f1d4df4b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 2 deletions

View File

@ -35,6 +35,12 @@ A flexible rollout strategy which combines all gradual rollout strategies in to
- **groupId** is used to ensure that different toggles will **hash differently** for the same user. The groupId defaults to _feature toggle name_, but the use can override it to _correlate rollout_ of multiple feature toggles.
- **rollout** The percentage (0-100) you want to enable the feature toggle for.
### Customize stickiness (beta)
By enabling the stickiness option on a custom context field you can use it together with the flexible rollout strategy. This will guarantee a consistent behavior for specific values of this context field. PS! support for this feature currently being supported by the following SDKs:
- [unleash-client-node](https://github.com/Unleash/unleash-client-node) (from v3.6.0)
## gradualRolloutUserId
The `gradualRolloutUserId` strategy gradually activates a feature toggle for logged in users. Stickiness is based on the user ID. The strategy guarantees that the same user gets the same experience every time across devices. It also assures that a user which is among the first 10% will also be among the first 20% of the users. That way, we ensure the users get the same experience, even if we gradually increase the number of users exposed to a particular feature. To achieve this, we hash the user ID and normalize the hash value to a number between 1 and 100 with a simple modulo operator.

View File

@ -19,7 +19,7 @@ If the toggle is considered **enabled**, the Unleash client will select the corr
If the toggle is considered **disabled** you will get the built-in `disabled` variant.
A json represntation of the empty variant will be the following:
A json representation of the empty variant will be the following:
```json
{
@ -28,7 +28,7 @@ A json represntation of the empty variant will be the following:
}
```
The actual representation of the built-in the client SDK will vary slighty, to honor best pratices in various languages.
The actual representation of the built-in the client SDK will vary slightly, to honor best practices in various languages.
> If you change the number of variants, it will affect variant allocations. This means that some of the users will be moved to the next variant.

View File

@ -9,6 +9,7 @@ const {
const COLUMNS = [
'name',
'description',
'stickiness',
'sort_order',
'legal_values',
'created_at',
@ -18,6 +19,7 @@ const TABLE = 'context_fields';
const mapRow = row => ({
name: row.name,
description: row.description,
stickiness: row.stickiness,
sortOrder: row.sort_order,
legalValues: row.legal_values ? row.legal_values.split(',') : undefined,
createdAt: row.created_at,
@ -63,6 +65,7 @@ class ContextFieldStore {
return {
name: data.name,
description: data.description,
stickiness: data.stickiness,
sort_order: data.sortOrder, // eslint-disable-line
legal_values: data.legalValues ? data.legalValues.join(',') : null, // eslint-disable-line
updated_at: data.createdAt, // eslint-disable-line

View File

@ -21,6 +21,10 @@ const contextSchema = joi
.unique()
.optional()
.items(joi.string().max(100)),
stickiness: joi
.boolean()
.optional()
.default(false),
})
.options({ allowUnknown: false, stripUnknown: true });

View File

@ -50,6 +50,7 @@ const variantsSchema = joi.object().keys({
value: joi.string().required(),
})
.optional(),
stickiness: joi.string().default('default'),
overrides: joi.array().items(
joi
.object()

View File

@ -59,6 +59,7 @@ test('should allow weightType=fix', t => {
name: 'variant-a',
weight: 1,
weightType: 'fix',
stickiness: 'default',
},
],
};
@ -103,6 +104,7 @@ test('should be possible to define variant overrides', t => {
name: 'variant-a',
weight: 1,
weightType: 'variable',
stickiness: 'default',
overrides: [
{
contextName: 'userId',

View File

@ -0,0 +1,18 @@
'use strict';
exports.up = function(db, cb) {
db.runSql(
`
ALTER TABLE context_fields ADD COLUMN IF NOT EXISTS stickiness boolean DEFAULT false
`,
cb,
);
};
exports.down = function(db, cb) {
db.runSql(
`
ALTER TABLE context_fields DROP COLUMN IF EXISTS stickiness;
`,
cb,
);
};

View File

@ -82,6 +82,25 @@ test.serial('should update context field with legalValues', async t => {
.expect(200);
});
test.serial('should create context field with stickiness', async t => {
t.plan(1);
const request = await setupApp(stores);
const name = 'with-sticky';
await request
.post('/api/admin/context')
.send({
name,
description: 'A context field supporting stickiness',
stickiness: true,
})
.set('Content-Type', 'application/json');
const res = await request.get(`/api/admin/context/${name}`);
const contextField = res.body;
t.is(contextField.stickiness, true);
});
test.serial('should not create context field when name is missing', async t => {
t.plan(0);
const request = await setupApp(stores);