quarantine v0.1.0 Quarantine

Quarantine

Quarantine is a tiny OTP application for feature toggles.

Currently it supports two strategies:

  • whitelist list of ids that can access some feature
  • percentage compute a score from the given id check with score <= percentage. Note that the combination of feature name and id produce a deterministic score

Setup

Add quarantine to your application deps

def deps do
  [
    {:quarantine, "~> 0.1.0"}
  ]
end

You can setup flags using config environment or provide a Quarantine.Driver to fetch configuration from an external source

When hardcoded config is good enough you can provide it as below

config :quarantine, 
   some_percentage_flag: 0.5,
   some_whitelist_flag: [1, 2, 3]
   other_whitelist_flag: ["08362804-bdc0-11e8-9407-24750000045e", "9fbc6c6e-f2dd-4f9d-8944-b81dd5a25fed"]

Usage

Simply call enabled?/2 where you want to split the control flow

Quarantine.enabled?(:some_percentage_flag, 1)
=> false

Quarantine.enabled?(:some_percentage_flag, 2)
=> true

Quarantine.enabled?(:some_whitelist_flag, 1)
=> true

Quarantine.enabled?(:some_whitelist_flag, 9)
=> false

When using percentage you can check current ids distribution if needed with scores/2

Quarantine.scores(:some_percentage_flag, [1, 2, 3])
=>  [{1, 0.9967498283360037},
     {2, 0.18811322194247349},
     {3, 0.30522621499961855}]

Refresh config without re-deploying your application

To do that you should provide an implementation of Quarantine.Driver that fetch flags configuration from a desired source like ets, s3, redis, consul, zookeeper, database or filesystem and add it to the config

Redis Driver example:

defmodule RedisDriver do
  @behaviour Quarantine.Driver

  def get_flags() do
    Redix.command!(:my_redix, ["GET", "my_flags"])
  end
end

S3 Driver example:

defmodule S3Driver do
  @behaviour Quarantine.Driver

  def get_flags() do
    "bucket"
    |> ExAws.S3.get_object("path")
    |> ExAws.request!()
  end
end

Note: get_flags must return a map which key is the flag and value is the config.

Then add it to :quarantine configuration:

config :quarantine, 
   driver: RedisDriver,
   pool_interval: 60_000 # in ms

When Quarantine starts it will run the driver at pool_interval to fetch flags updates

Link to this section Summary

Functions

Check if the given feature is enabled or disabled for the given id

Compute the scores of the given feature for the ids

Link to this section Types

Link to this type feature_name()
feature_name() :: atom() | String.t()

Link to this section Functions

Link to this function enabled?(server \\ Server, feature, id)
enabled?(pid(), feature_name(), String.t()) :: boolean()

Check if the given feature is enabled or disabled for the given id.

Returns true or false.

Examples

iex> Quarantine.enabled?(:some_feature, 1) false

Link to this function scores(feature, ids)
scores(atom(), [integer() | String.t()]) :: float()

Compute the scores of the given feature for the ids.

Returns float between 0.0 and 1.0

Examples

iex> Quarantine.scores(:some_feature, [10, 11]) [{10, 0.21571679255359733}, {11, 0.7114824139772641}]

iex> Quarantine.scores(:other_feature, [10, 11]) [{10, 0.7513847562371252}, {11, 0.9227740901808195}]