Skip to content

Instantly share code, notes, and snippets.

@ktheory
Last active August 29, 2015 14:06
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ktheory/024840996271390b4dc1 to your computer and use it in GitHub Desktop.
Save ktheory/024840996271390b4dc1 to your computer and use it in GitHub Desktop.
Redis indicators
# app/models/indicator.rb
##
# Example usage:
# indicator = Indicator::UserActivity.new(user_id)
#
# When a new activity is added to a user's feed:
# indicator.increment
#
# When a user views their unseen activity:
# indicator.clear
#
# Does the user have any unseen activity?
# indicator.set?
#
# How many unseen activities does the user have? (for the iOS app)
# indicator.value
module Indicator
class Base # Abstract base class
# Store at most this many entries per hash.
# Allows ~7x memory compression with small CPU trade-off.
# Benchmark: http://git.io/Yo_lYA
# Docs: http://redis.io/topics/memory-optimization
MAX_HASH_ENTRIES = 512
attr_accessor :obj_id
def initialize(obj)
self.obj_id = obj.respond_to?(:id) ? obj.id : obj.to_i
end
# Increment ids in bulk
def self.increment(ids)
redis.pipelined do
Array(ids).each {|id| new(id).increment }
end
end
def key_prefix
raise NotImplementedError
end
def hash_key
"#{key_prefix}:#{obj_id/MAX_HASH_ENTRIES}"
end
def clear
@value = nil
redis.hdel(hash_key, obj_id)
end
def increment
@value = nil
redis.hincrby(hash_key, obj_id, 1)
end
# Directly set the value. Only used for backfilling
def set(value)
@value = nil
redis.hset(hash_key, obj_id, value)
end
def value
@value ||= redis.hget(hash_key, obj_id).to_i
rescue ::Redis::BaseError
# Return 0 if anything goes wrong
# Prevent errors from bubbling up to views
0
end
def set?
value > 0
end
end
# Concrete classes must implement the `key_prefix` method
class UserActivity < Base
def key_prefix; 'indicators/user_activity'; end
end
end
Copyright 2014 Kickstarter, Inc.
Released under an MIT License.
# app/models/user.rb
class User < ActiveRecord::Base
def activity_indicator
@activity_indicator ||= Indicator::UserActivity.new(id)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment