Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add new Flexible Rollout Strategy #517

Merged
merged 3 commits into from
Oct 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/activation-strategies.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@ Active for users with a `userId` defined in the `userIds` list. Typically I want

- userIds - _List of user IDs you want the feature toggle to be enabled for_

## flexibleRollout

A flexible rollout strategy which combines all gradual rollout strategies in to a single strategy (and will in time replace them). This strategy have different options for how you want to handle the stickiness, and have sane default mode.

**Parameters**

- **stickiness** is used to define how we guarantee consistency for gradual rollout. The same userId and the same rollout percentage should give predictable results. Configuration that should be supported:
- **DEFAULT** - Unleash chooses the first value present on the context in defined order userId, sessionId, random.
- **USERID** - guaranteed to be sticky on userId. If userId not present the behaviour would be false
- **SESSIONID - **guaranteed to be sticky on sessionId. If sessionId not present the behaviour would be false.
- **RANDOM** - no stickiness guaranteed. For every isEnabled call it will yield a random true/false based on the selected rollout percentage.
- **groupId** is used to ensure that different toggles will **hash differently** for the same user. The groupId defaults to _feature toggle name_, but is overridable by the user to _correlate rollout_ of multiple feature toggles.
- **rollout** The percentage (0-100) you want to enable the feature toggle for.

## 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 normalise the hash value to a number between 1 and 100 with a simple modulo operator.
Expand Down
64 changes: 64 additions & 0 deletions migrations/20191023184858-flexible-rollout-strategy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
'use strict';

const flexibleRollout = require('./flexible-rollout-strategy.json');
const async = require('async');

function insertStrategySQL(strategy) {
return `
INSERT INTO strategies (name, description, parameters, built_in)
SELECT '${strategy.name}', '${strategy.description}', '${JSON.stringify(
strategy.parameters
)}', 1
WHERE
NOT EXISTS (
SELECT name FROM strategies WHERE name = '${strategy.name}'
);`;
}

function insertEventsSQL(strategy) {
return `
INSERT INTO events (type, created_by, data)
SELECT 'strategy-created', 'migration', '${JSON.stringify(strategy)}'
WHERE
NOT EXISTS (
SELECT name FROM strategies WHERE name = '${strategy.name}'
);`;
}

function removeEventsSQL(strategy) {
return `
INSERT INTO events (type, created_by, data)
SELECT 'strategy-deleted', 'migration', '${JSON.stringify(strategy)}'
WHERE
EXISTS (
SELECT name FROM strategies WHERE name = '${
strategy.name
}' AND built_in = 1
);`;
}

function removeStrategySQL(strategy) {
return `
DELETE FROM strategies
WHERE name = '${strategy.name}' AND built_in = 1`;
}

exports.up = function(db, callback) {
async.series(
[
db.runSql.bind(db, insertEventsSQL(flexibleRollout)),
db.runSql.bind(db, insertStrategySQL(flexibleRollout)),
],
callback
);
};

exports.down = function(db, callback) {
async.series(
[
db.runSql.bind(db, removeEventsSQL(flexibleRollout)),
db.runSql.bind(db, removeStrategySQL(flexibleRollout)),
],
callback
);
};
24 changes: 24 additions & 0 deletions migrations/flexible-rollout-strategy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "flexibleRollout",
"description": "Gradually activate feature toggle based on sane stickiness",
"parameters": [
{
"name": "rollout",
"type": "percentage",
"description": "",
"required": false
},
{
"name": "stickiness",
"type": "string",
"description": "Used define stickiness. Possible values: default, userId, sessionId, random",
"required": true
},
{
"name": "groupId",
"type": "string",
"description": "Used to define a activation groups, which allows you to correlate across feature toggles.",
"required": true
}
]
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
"prometheus-gc-stats": "^0.6.1",
"response-time": "^2.3.2",
"serve-favicon": "^2.5.0",
"unleash-frontend": "3.2.7",
"unleash-frontend": "3.2.8",
"yargs": "^14.0.0"
},
"devDependencies": {
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5906,10 +5906,10 @@ universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"

unleash-frontend@3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/unleash-frontend/-/unleash-frontend-3.2.7.tgz#ec2af024229589d2f070e6961de65bb063375b40"
integrity sha512-30fZKazTiPbTL2335T6B0EBjQbqezlZ/wb9OFGSIjIA6S14/9+5hL9qx6E6V2dCtX0FX32pGGXnSrjuzq2on7Q==
unleash-frontend@3.2.8:
version "3.2.8"
resolved "https://registry.yarnpkg.com/unleash-frontend/-/unleash-frontend-3.2.8.tgz#b8dedc23d3c44cac313c6da617940b5ea5162b83"
integrity sha512-QeXWOE+nxtumZYOyt9KZsIVpnaQPgEibAsvGhsS0t8ZidSnUybPbY/NE82IDOVneKO34kwfRCTnIkiQQLc4EEw==

unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
Expand Down