defmodule Unleash.Strategy.FlexibleRollout do
@moduledoc """
Can depend on `:user_id` or `:session_id` in `t:Unleash.context/0`
Based on the
[`flexibleRollout`](https://unleash.github.io/docs/activation_strategy#flexiblerollout)
strategy.
"""
use Unleash.Strategy, name: "FlexibleRollout"
alias Unleash.Strategy.Utils
def enabled?(%{"rollout" => percentage} = params, context) when is_number(percentage) do
sticky_value =
params
|> Map.get("stickiness", "")
|> stickiness(context)
group = Map.get(params, "groupId", Map.get(params, :feature_toggle, ""))
if sticky_value do
{percentage > 0 and Utils.normalize(sticky_value, group) <= percentage,
%{
group: group,
percentage: percentage,
sticky_value: sticky_value,
stickiness: Map.get(params, "stickiness")
}}
else
{false,
%{
group: group,
percentage: percentage,
sticky_value: sticky_value,
stickiness: Map.get(params, "stickiness")
}}
end
end
def enabled?(%{"rollout" => percentage} = params, context),
do: enabled?(%{params | "rollout" => Utils.parse_int(percentage)}, context)
defp stickiness("default", ctx), do: Map.get(ctx, :user_id, Map.get(ctx, :session_id, random()))
defp stickiness("userId", ctx), do: ctx[:user_id]
defp stickiness("sessionId", ctx), do: ctx[:session_id]
defp stickiness("random", _ctx), do: random()
defp stickiness("", ctx), do: stickiness("default", ctx)
defp random,
do: Integer.to_string(round(:rand.uniform() * 100) + 1)
end