pluggit/feature-balancer

This PHP library will allow to switch on/off or balance with a percentage between features

3.0.0 2019-05-30 08:17 UTC

This package is not auto-updated.

Last update: 2024-04-08 13:25:27 UTC


README

This PHP library will allow to switch on/off or balance with a percentage between features

Build Status Scrutinizer Code Quality Code Coverage

TLDR;

$balancer = (new BalancerBuilder())
    ->withLogger($logger, LogLevel::INFO)
    ->withMonitor($monitor, "my_app.feature_balanced")
    ->create([
        "home_banner" => [
            "do_not_show"   => 20,
            "amazing_offer" => 80,
        ],
        "after_update_email" => [
            "normal"        => 60,
            "special_offer" => 30,
            "do_not_send"   => 10,
        ]
    ]);

/**
 * Random Non-deterministic balance
 * - 20% change to get "do_not_show", 80% chance to get "amazing_offer"
 */
$path = $balancer->get("home_banner");

/**
 * Deterministic balance, given a configuration and a valid seed, 
 * you'll always get the same result
 *
 * Valid seeds are non-empty strings and unsigned numbers
 */
$path = $balancer->get("after_update_email", 78549612);
$path = $balancer->get("after_update_email", -4.75);
$path = $balancer->get("after_update_email", "my_user@example.com");

Building the balancer

The library comes with a builder to ease the creation of the balancer.

$balancer = (new BalancerBuilder())->create();

Adding logging

If you install the Psr\Log library you can add logging to every decision made by the balancer. You can choose the log level that will be use to record log entries

// Add a logger when building the balancer
$balancer = (new BalancerBuilder())->->withLogger($logger, LogLevel::DEBUG)->create($config);

/** 
 * This will log: "Feature path returned from the balancer: home_banner -> amazing_offer"
 * Plus some context information:
 * - feature
 * - path
 * - seed
 */
$balancer->get("home_banner", 9874562);

Adding monitoring

If you install the pluggit\monitoring library you can add monitoring to every decision made by the balancer.

You have to choose the metric name to increment

// Add a monitor when building the balancer
$balancer = (new BalancerBuilder())->->withMonitor($monitor, "balanced_feature")->create($config);

/** 
 * This will increment the metric: "balanced_feature", plus some tags
 * - feature
 * - path
 * - seed: true/false
 */
$balancer->get("home_banner", 9874562);

Hiding exceptions

If you don't wan't the feature balancer to throw exceptions, you can silence it with the ExceptionSilencerDecorator. It will log the errors and return "" as path for the requested feature

// Add a monitor when building the balancer
$balancer = (new BalancerBuilder())->->withoutExceptions()->create($config);

/** 
 * Requesting an unknown feature will return an empty string -> ""
 */
$balancer->get("unknown_feature");

Adding features to the balancer

You can always add features to the balancer trough the method add. The rules are:

  • Every feature must have a non-empty unique string identifier, adding the same feature will overwrite the previous configuration
  • Every feature must have at least one possible path
  • Every feature path must have a non-empty unique string identifier for the given feature
  • Every path has assigned a percentage
  • The percentage for every path has to be an unsigned integer between 0 and 100
  • All the path percentages must sum exactly 100

Any violation of the following rules will make the balancer throw a Cmp\FeatureBalancer\Exception\InvalidArgumentException exception

Valid examples

$balancer->add("my_super_feature",  [
    "do_not_show"   => 20,
    "amazing_offer" => 80,
]);

$balancer->add("my_super_feature",  [
    "do_not_show"   => 0,
    "amazing_offer" => 100,
]);

$balancer->add("my_super_feature",  [
    "amazing_offer" => 100,
]);

Invalid examples

// No paths defined
$balancer->add("my_super_feature",  []);

// Percentages sum 90
$balancer->add("my_super_feature",  [
    "do_not_show"   => 90,
]);

// Percentages sum 140
$balancer->add("my_super_feature",  [
    "do_not_show"   => 60,
    "amazing_offer" => 80,
]);

// Percentages is not a valid unsigned integer
$balancer->add("my_super_feature",  [
    "do_not_show"   => "60",
    "amazing_offer" => 40,
]);

Getting a path

Once you have configured a feature, you can request a path to the balancer

Random Non-deterministic retrieval

If you don't pass a seed, the path will be choosen randomly taking into account the defined percentages

$path = $balancer->get("home_banner");

Seed based deterministic retrieval

If you pass a seed, the path will be decided using a simple yet infallible algorithm so that for every given configuration and seed, it will always choose the same path

NOTE This means that the path can change if either the configuration or the seed changes

You can pass both signed numbers (integers and doubles) or non-empty strings as seed

$path = $balancer->get("after_update_email", 78549612);
$path = $balancer->get("after_update_email", -23.54);
$path = $balancer->get("after_update_email", "my_user@example.com");