FLAG YOUR FEATURES WITH
ROLLOUT AND DEGRADE
Ariel Caplan
Slide 2
Slide 2 text
WHAT ARE FEATURE FLAGS?
• Turn bits of code on and off
• On/Off
• This/That
Slide 3
Slide 3 text
• Experimental Code
• Syncing apps in an SOA ecosystem
WHY FEATURE FLAGS?
Client Service
v1
v2
Slide 4
Slide 4 text
WHY FEATURE FLAGS?
• Experimental Code
• Syncing apps in an SOA ecosystem
• Consuming internal services (where you don’t have control)
Client Service
v1
v2
Slide 5
Slide 5 text
• Experimental Code
• Syncing apps in an SOA ecosystem
• Consuming internal services (where you don’t have control)
• Consuming external services (which experience downtime)
WHY FEATURE FLAGS?
Client Service
Slide 6
Slide 6 text
• Experimental Code
• Syncing apps in an SOA ecosystem
• Consuming internal services (where you don’t have control)
• Consuming external services (which experience downtime)
• Debugging tools
WHY FEATURE FLAGS?
Slide 7
Slide 7 text
ROLLOUT REQUIRES REDIS
rollout = Rollout.new(redis)
!
!
Technically it doesn’t require redis… but use it anyway.
Slide 8
Slide 8 text
ACTIVATION/DEACTIVATION
# activate for all users
rollout.activate(:chat)
!
# deactivate for all users
rollout.deactivate(:chat)
Slide 9
Slide 9 text
A/B TESTING
# activate for a percentage of users
rollout.activate_percentage(:chat, 20)
!
# check if the user gets the new feature!
rollout.active?(:chat, User.first)
Slide 10
Slide 10 text
WHERE TO INSERT
BRANCH POINTS?
Slide 11
Slide 11 text
BRANCH POINT: CONTROLLER
class ExperimentalController < ApplicationController
!
def index
if rollout.active?(:my_feature)
@entities = MyFeature.get_entities(params)
respond_with @entities
else
head(:service_unavailable)
end
end
!
end
Slide 12
Slide 12 text
BRANCH POINT: MODELS
class ResponseFormatter
!
attr_reader :array
!
def initialize(array)
@array = array
end
!
def output
if rollout.active?(:safe_json_format)
{ 'array' => array }
else
array
end
end
!
end
Slide 13
Slide 13 text
#PROTIP: USE HUBOT
class FeaturesController < ApplicationController
!
def update
rollout.activate(params[:id].to_sym)
head :ok
end
!
def destroy
rollout.deactivate(params[:id].to_sym)
head :ok
end
!
end
WRAP YOUR UNRELIABLE SERVICES
if rollout.active?(:my_feature)
data = degrade_my_feature.perform do
Net::HTTP.get('mega-downtime.com', '/data.json')
end
end
Slide 17
Slide 17 text
DEGRADE DOESN’T
AFFECT YOUR CODE
def perform
begin
mark_request
yield
rescue *@errors => e
mark_failure
raise e
end
end
https://github.com/jamesgolick/degrade/blob/master/lib/degrade.rb#L12-L20