Class: Retained::Tracker
- Inherits:
-
Object
- Object
- Retained::Tracker
- Defined in:
- lib/retained/tracker.rb
Instance Attribute Summary collapse
-
#config ⇒ Object
Returns the value of attribute config.
Instance Method Summary collapse
-
#active?(entity, group: nil, period: Time.now) ⇒ Boolean
Returns true if the entity was active in the given period, or now if no period is provided.
- #configure {|config| ... } ⇒ Object
-
#entity_index(entity, group) ⇒ Object
Returns the index (offset) of the entity within the group.
-
#groups ⇒ Object
Returns an array of all groups.
-
#initialize(config = Configuration.new) ⇒ Tracker
constructor
A new instance of Tracker.
-
#key_period(group, period) ⇒ Object
Returns the key for the group at the period.
-
#retain(entity, group: 'default', period: Time.now) ⇒ Object
Tracks the entity as active at the period, or now if no period is provided.
-
#total_active(group: 'default', period: Time.now) ⇒ Object
Total active entities in the period, or now if no period, is provided.
-
#unique_active(group: 'default', start:, stop: Time.now) ⇒ Object
Returns the total number of unique active entities between the start and end periods (inclusive), or now if no stop period is provided.
Constructor Details
#initialize(config = Configuration.new) ⇒ Tracker
Returns a new instance of Tracker.
10 11 12 |
# File 'lib/retained/tracker.rb', line 10 def initialize(config = Configuration.new) @config = config end |
Instance Attribute Details
#config ⇒ Object
Returns the value of attribute config.
8 9 10 |
# File 'lib/retained/tracker.rb', line 8 def config @config end |
Instance Method Details
#active?(entity, group: nil, period: Time.now) ⇒ Boolean
Returns true if the entity was active in the given period, or now if no period is provided. If a group or an array of groups is provided activity will only be considered based on those groups.
52 53 54 55 56 57 58 59 60 |
# File 'lib/retained/tracker.rb', line 52 def active?(entity, group: nil, period: Time.now) group = [group] if group.is_a?(String) group = groups if group == [] || !group group.to_a.each do |g| return true if config.redis_connection.getbit(key_period(g, period), entity_index(entity, g)) == 1 end false end |
#configure {|config| ... } ⇒ Object
14 15 16 |
# File 'lib/retained/tracker.rb', line 14 def configure yield(config) end |
#entity_index(entity, group) ⇒ Object
Returns the index (offset) of the entity within the group.
Thanks to crashlytics for the monotonic_zadd approach taken here www.slideshare.net/crashlytics/crashlytics-on-redis-analytics
71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/retained/tracker.rb', line 71 def entity_index(entity, group) monotonic_zadd = <<LUA local sequential_id = redis.call('zscore', KEYS[1], ARGV[1]) if not sequential_id then sequential_id = redis.call('zcard', KEYS[1]) redis.call('zadd', KEYS[1], sequential_id, ARGV[1]) end return sequential_id LUA key = "#{config.prefix}:entity_ids:#{group}" config.redis_connection.eval(monotonic_zadd, [key], [entity.to_s]).to_i end |
#groups ⇒ Object
Returns an array of all groups
63 64 65 |
# File 'lib/retained/tracker.rb', line 63 def groups config.redis_connection.smembers "#{config.prefix}:groups" end |
#key_period(group, period) ⇒ Object
Returns the key for the group at the period. All periods are internally stored relative to UTC.
87 88 89 |
# File 'lib/retained/tracker.rb', line 87 def key_period(group, period) "#{config.prefix}:#{group}:#{period_start(group, period).to_i}" end |
#retain(entity, group: 'default', period: Time.now) ⇒ Object
Tracks the entity as active at the period, or now if no period is provided.
20 21 22 23 |
# File 'lib/retained/tracker.rb', line 20 def retain(entity, group: 'default', period: Time.now) index = entity_index(entity, group) config.redis_connection.setbit key_period(group, period), index, 1 end |
#total_active(group: 'default', period: Time.now) ⇒ Object
Total active entities in the period, or now if no period, is provided.
27 28 29 |
# File 'lib/retained/tracker.rb', line 27 def total_active(group: 'default', period: Time.now) config.redis_connection.bitcount key_period(group, period) end |
#unique_active(group: 'default', start:, stop: Time.now) ⇒ Object
Returns the total number of unique active entities between the start and end periods (inclusive), or now if no stop period is provided.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/retained/tracker.rb', line 34 def unique_active(group: 'default', start:, stop: Time.now) keys = [] start = period_start(group, start) while (start <= stop) keys << key_period(group, start) start += seconds_in_reporting_interval(config.group(group).reporting_interval) end return 0 if keys.length == 0 temp_bitmap do |key| config.redis_connection.bitop 'OR', key, *keys config.redis_connection.bitcount key end end |