Class: Rollout

Inherits:
Object
  • Object
show all
Defined in:
lib/rollout.rb,
lib/rollout/feature.rb,
lib/rollout/version.rb

Defined Under Namespace

Classes: Error, Feature

Constant Summary collapse

VERSION =
'0.3.0'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(storage) ⇒ Rollout

Returns a new instance of Rollout.



14
15
16
17
18
# File 'lib/rollout.rb', line 14

def initialize(storage)
  @storage = storage
  @cache_enabled = false
  @degrade_enabled = false
end

Instance Attribute Details

#storageObject (readonly)

Returns the value of attribute storage.



12
13
14
# File 'lib/rollout.rb', line 12

def storage
  @storage
end

Instance Method Details

#activate(feature_name, percentage = 100) ⇒ Object



36
37
38
39
40
41
42
43
44
# File 'lib/rollout.rb', line 36

def activate(feature_name, percentage=100)
  data = { percentage: percentage }
  feature = Feature.new(feature_name, data)
  @cache[feature_name] = {
    feature: feature,
    timestamp: Time.now.to_i
  } if @cache_enabled
  save(feature) == "OK"
end

#activate_percentage(feature_name, percentage) ⇒ Object



46
47
48
# File 'lib/rollout.rb', line 46

def activate_percentage(feature_name, percentage)
  activate(feature_name, percentage)
end

#active?(feature_name, determinator = nil) ⇒ Boolean

Returns:

  • (Boolean)


54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/rollout.rb', line 54

def active?(feature_name, determinator = nil)
  feature = get(feature_name, determinator)
  return false unless feature

  active = feature.active?(determinator)

  if active && @degrade_enabled
    feature.add_request
    save(feature)
  end

  active
end

#clean_cacheObject



94
95
96
97
98
# File 'lib/rollout.rb', line 94

def clean_cache
  return unless @cache_enabled

  @cache = {}
end

#deactivate(feature_name) ⇒ Object



50
51
52
# File 'lib/rollout.rb', line 50

def deactivate(feature_name)
  del(feature_name)
end

#featuresObject



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/rollout.rb', line 81

def features
  keys = @storage.keys("#{key_prefix}:*")
  return [] if keys.empty?

  keys.map do |key|
    data = @storage.get(key)
    next unless data

    feature_name = key.gsub("#{key_prefix}:", '')
    Feature.new(feature_name, JSON.parse(data, symbolize_names: true)).to_h
  end
end

#migrate_from_rollout_formatObject



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/rollout.rb', line 100

def migrate_from_rollout_format
  keys = @storage.keys('feature:*')

  keys.each do |old_key|
    new_key = old_key.gsub('feature:', 'feature-rollout-redis:')
    old_data = @storage.get(old_key)

    if old_data
      percentage = old_data.split('|')[0].to_i

      new_data = {
        percentage: percentage,
        requests: 0,
        errors: 0
      }.to_json

      @storage.set(new_key, new_data)

      puts "Migrated key: #{old_key} to #{new_key} with data #{new_data}"
    end
  end
end

#with_cache(expires_in: 300) ⇒ Object



20
21
22
23
24
25
26
# File 'lib/rollout.rb', line 20

def with_cache(expires_in: 300)
  @cache_enabled = true
  @cache_time = expires_in
  @cache = {}

  self
end

#with_degrade(min: 100, threshold: 0.1) ⇒ Object



28
29
30
31
32
33
34
# File 'lib/rollout.rb', line 28

def with_degrade(min: 100, threshold: 0.1)
  @degrade_enabled = true
  @degrade_min = min
  @degrade_threshold = threshold

  self
end

#with_feature_flag(feature_name, determinator = nil, &block) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/rollout.rb', line 68

def with_feature_flag(feature_name, determinator = nil, &block)
  yield if active?(feature_name, determinator)
rescue => e
  feature = get(feature_name, determinator)
  if @degrade_enabled && feature
    feature.add_error
    save(feature)

    deactivate(feature_name) if degraded?(feature)
  end
  raise e
end