Class: Trebuchet::Backend::Redis

Inherits:
Object
  • Object
show all
Defined in:
lib/trebuchet/backend/redis.rb

Direct Known Subclasses

RedisCached, RedisHammerspaced

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Redis

Returns a new instance of Redis.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/trebuchet/backend/redis.rb', line 8

def initialize(*args)
  @namespace = 'trebuchet/'
  begin
    if args.first.is_a?(Hash) && (client = args.first[:client]) && (client.is_a?(Redis) || client.is_a?(MockRedis))
      # ignore other args and use provided Redis connection
      @options = args.first
      @redis = args.first[:client]
    else
      @redis = Redis.new(*args)
    end
    unless @options && @options[:skip_check]
      # raise error if not connectedUncaught ReferenceError: google is not defined
      @redis.exists(feature_names_key) # @redis.info is slow and @redis.client.connected? is NOT reliable
    end
  rescue Exception => e
    raise Trebuchet::BackendInitializationError, e.message
  end
end

Instance Attribute Details

#namespaceObject

Returns the value of attribute namespace.



6
7
8
# File 'lib/trebuchet/backend/redis.rb', line 6

def namespace
  @namespace
end

Instance Method Details

#append_strategy(feature_name, strategy, options = nil) ⇒ Object



54
55
56
57
58
59
60
# File 'lib/trebuchet/backend/redis.rb', line 54

def append_strategy(feature_name, strategy, options = nil)
  @redis.srem(archived_feature_names_key, feature_name)
  @redis.hset(feature_key(feature_name), strategy, [options].to_json) # have to put options in container for json
  @redis.sadd(feature_names_key, feature_name)
  store_history(feature_name)
  update_sentinel
end

#get_all_history(include_archived = false) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/trebuchet/backend/redis.rb', line 98

def get_all_history(include_archived = false)
  history = []

  features = @redis.smembers(feature_names_key)
  features += @redis.smembers(archived_feature_names_key) if include_archived

  result = @redis.pipelined do
    features.each do |feature_name|
      @redis.smembers(feature_history_key(feature_name))
    end
  end

  features.zip(result).each do |feature_name, timestamps|
    timestamps.each do |timestamp|
      history << [timestamp.to_i, feature_name]
    end
  end

  # sort in reverse timestamp order
  history.sort! { |x,y| y.first <=> x.first }
end

#get_archived_feature_namesObject



71
72
73
# File 'lib/trebuchet/backend/redis.rb', line 71

def get_archived_feature_names
  @redis.smembers(archived_feature_names_key)
end

#get_feature_namesObject



67
68
69
# File 'lib/trebuchet/backend/redis.rb', line 67

def get_feature_names
  @redis.smembers(feature_names_key)
end

#get_history(feature_name) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/trebuchet/backend/redis.rb', line 89

def get_history(feature_name)
  [].tap do |history|
    @redis.smembers(feature_history_key(feature_name)).sort.each do |timestamp|
      h = @redis.hgetall(feature_history_key(feature_name, timestamp))
      history << [timestamp.to_i, unpack_strategy(h)]
    end
  end
end

#get_sentinelObject



124
125
126
# File 'lib/trebuchet/backend/redis.rb', line 124

def get_sentinel
  @redis.get(sentinel_key) || Time.now.to_i
end

#get_strategy(feature_name) ⇒ Object



27
28
29
30
# File 'lib/trebuchet/backend/redis.rb', line 27

def get_strategy(feature_name)
  return nil unless h = @redis.hgetall(feature_key(feature_name))
  unpack_strategy(h)
end

#remove_feature(feature_name) ⇒ Object



75
76
77
78
79
80
# File 'lib/trebuchet/backend/redis.rb', line 75

def remove_feature(feature_name)
  @redis.del(feature_key(feature_name))
  @redis.srem(feature_names_key, feature_name)
  @redis.sadd(archived_feature_names_key, feature_name)
  update_sentinel
end

#remove_strategy(feature_name) ⇒ Object



62
63
64
65
# File 'lib/trebuchet/backend/redis.rb', line 62

def remove_strategy(feature_name)
  @redis.del(feature_key(feature_name))
  update_sentinel
end

#set_strategy(feature_name, strategy, options = nil) ⇒ Object



48
49
50
51
52
# File 'lib/trebuchet/backend/redis.rb', line 48

def set_strategy(feature_name, strategy, options = nil)
  remove_strategy(feature_name)
  append_strategy(feature_name, strategy, options)
  update_sentinel
end

#store_history(feature_name) ⇒ Object



82
83
84
85
86
87
# File 'lib/trebuchet/backend/redis.rb', line 82

def store_history(feature_name)
  timestamp = Time.now.to_i
  h = @redis.hgetall(feature_key(feature_name))
  @redis.hmset(feature_history_key(feature_name, timestamp), *h.to_a.flatten)
  @redis.sadd(feature_history_key(feature_name), timestamp) # subtle
end

#unpack_strategy(options) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/trebuchet/backend/redis.rb', line 32

def unpack_strategy(options)
  return nil unless options.is_a?(Hash)
  [].tap do |a|
    options.each do |k, v|
      begin
        key = k.to_sym
        value = JSON.load(v).first # unpack from array
        a << key
        a << value
      rescue
        # if it can't parse the JSON, skip it
      end
    end
  end
end

#update_sentinelObject



120
121
122
# File 'lib/trebuchet/backend/redis.rb', line 120

def update_sentinel
  @redis.set(sentinel_key, Time.now.to_i)
end