Beta version.
Hanoi is a port of rollout gem from James Golick and Eric Rafaloff.
The idea behind it is to ease a simple way to enable/disable functionalities to a subset of users in a production (or any other) environment. This is in general handy upon deploying a new version of your product, in order to test the new functionalities in a subset of users. It could be useful as well as ACL mechanism.
- Enable a functionality globally (for every user using the system).
- Enable a functionality to a percentage of users via Cyclic Redundancy Check(user identifier) % 100.
- Enable a functionality to a percentage of users via a predefined rule using a Regular Expression.
- Enable a functionality to specific user identifiers.
- Variants support (new in 0.0.4): inspired in feature by Esty and sixpack,
hanoi
now supports variant for providing to users different options for an experiment.
- Check if the functionality A is enabled for user B.
rollout.is_enabled('A', B)
- Pre-check while executing a function (functionality A) that user B (received as parameter in the function call) is granted permissions.
@roll.check('A', 1) # Check if user B (argument 1) is granted permissions to execute A
def execute_a_logic(user):
pass # Business logic here
execute_a_logic(B)
- Pre-check to ensure user B (attached to the process/thread) can execute functionality A (ACL mechanism). Be aware if your environment requires thread-safe behavior.
rollout.set_current_id(B)
@roll.check('A') # Check if the current user (B) is granted permissions to execute A
def execute_a_logic():
pass # Business logic here
execute_a_logic()
- Retrieving a valid variant for an experiment A for user B
variant = rollout.variant('A', B)
# Setting the configuration
# -------------------------
# bootstrap.py
import re
import hanoi
rollout = hanoi.Rollout(hanoi.RedisHighPerfBackEnd())
rollout.add_func(
'cdc_on', # Functionality name (CDC on)
percentage=80, # Percentage for toggle ON
variants=('foo', 'bar') # Valid variants in case of toggle ON
)
rollout.register('cdc_on', '447568110000') # Register a specific user
rollout.register('cdc_on', re.compile(r'01$') # Register a subset of users
def get_rollout():
return rollout
# Using Rollout
# -------------
# service.py
import bootstrap
roll = bootstrap.get_rollout()
# Define the current user (kind of ThreadLocal)
roll.set_current_id('444401')
@roll.check('cdc_on') # Check if the current user is registerd to `cdc_on`
def execute_cdc_logic():
pass
# Based on the rules defined in bootstrap.py,
# the decorator will not allow the function execution,
# as zlib.crc32('444401') % 100 = 89, and the predefined percentage is 80
execute_cdc_logic()
# Check if it's enabled `cdc_on` to the user `44488`
# Based on the rules defined in bootstrap.py, it will return False
print roll.is_enabled('cdc_on', '44488')
# Check if it's enabled `cdc_on` to the second parameter
@roll.check('cdc_on', 2)
def execute_again_cdc_logic(parameter, user):
return "I'm in"
# Based on the rules defined in bootstrap.py,
# the decorator will allow the function execution, as 443301 matches the reg expr.
print execute_again_cdc_logic('foo', '443301')
# Get a valid variant for user `443301`
print roll.variant('cdc_on', '443301')
Currently there're three implemented BackEnds:
-
MemoryBackEnd: useful for development or where you have predefined rules and don't need to share information between different processes.
-
RedisBackEnd: useful for distributed environments, where you need to easily update functionalities, rules or users attached to a specific functionality.
-
RedisHighPerfBackEnd: useful for distributed environments and high performance. It uses SET to store users and reduce significantly the time to verify an user. Check and execute
benchmark.py
file for details.
- Finish unit testing Rollout class
- Finish unit testing Function class
- Implement Redis BackEnd
- Finish unit testing RedisBackEnd class
- Document the different use cases and when to use both backends
- Integrate travis.ci
- Upload a beta version to pypi
- Think about a cooler name 😉. We'll stay with hanoi
- Write a blog post