Module: RedisSupport::ClassMethods
- Included in:
- RedisSupport
- Defined in:
- lib/redis_support/locks.rb,
lib/redis_support/class_extensions.rb
Instance Method Summary collapse
-
#acquire_redis_lock(key_to_lock, expiration = 30, interval = 1) ⇒ Object
Acquire a lock on a key in our Redis database.
-
#acquire_redis_lock_nonblock(key_to_lock, expiration = 30) ⇒ Object
Attempt to acquire a lock on a key in our Redis database.
- #has_redis_lock?(locked_key) ⇒ Boolean
- #is_redis_fulfilling_locked?(locked_key) ⇒ Boolean
- #is_redis_locked?(locked_key) ⇒ Boolean
- #locked_until(locked_key) ⇒ Object
- #redefine_redis_key(name, keystruct) ⇒ Object
- #redis ⇒ Object
- #redis=(connection) ⇒ Object
-
#redis_key(name, keystruct) ⇒ Object
Goal is to allow a class to declare a redis key/property The key is a colon delimited string where variables are listed are upper case (underscores inbetween) and non variables are completely lower case (underscores inbetween or appending/prepending).
-
#redis_lock(key_to_lock, expiration = 30, interval = 1) ⇒ Object
Lock a block of code so it can only be accessed by one thread in our system at a time.
-
#redis_lock_nonblock(key_to_lock, expiration = 30) ⇒ Object
Attempt to lock a block of code so it can only be accessed by one thread in our system at a time.
-
#redis_throttle(key_to_lock, expiration = 30) ⇒ Object
Throttle a block of code so it is only executed at most every ‘expiration` seconds.
-
#release_redis_lock(locked_key) ⇒ Object
See docs for acquire_redis_lock above.
Instance Method Details
#acquire_redis_lock(key_to_lock, expiration = 30, interval = 1) ⇒ Object
Acquire a lock on a key in our Redis database. This is a blocking call. It sleeps until the lock has been successfully acquired.
Basic usage:
acquire_redis_lock( key.my_key )
# do some stuff on my_key
release_redis_lock( key.my_key )
interval - sleep interval for checking the lock’s status.
Returns nothing.
53 54 55 56 57 |
# File 'lib/redis_support/locks.rb', line 53 def acquire_redis_lock( key_to_lock, expiration = 30, interval = 1 ) until acquire_redis_lock_nonblock( key_to_lock, expiration ) sleep interval end end |
#acquire_redis_lock_nonblock(key_to_lock, expiration = 30) ⇒ Object
Attempt to acquire a lock on a key in our Redis database.
Returns true on success and false on failure
Described in detail here:
http://code.google.com/p/redis/wiki/SetnxCommand
key_to_lock - the key to lock. the actual key for the lock in redis will
be this value with 'lock.' prepended, which lets this whole
acquire_lock business act like a standard ruby object or
synchronize lock. Also it ensures that all locks in the database
can be easily viewed using redis.keys("lock.*")
expiration - the expiration for the lock, expressed as an Integer. default is
30 seconds from when the lock is acquired. Note that this is the
amount of time others will wait for you, not the amount of time
you will wait to acquire the lock.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/redis_support/locks.rb', line 78 def acquire_redis_lock_nonblock( key_to_lock, expiration = 30 ) key = lock_key( key_to_lock ) if redis.setnx key, timeout_i( expiration ) return true else if redis.get( key ).to_i < Time.now.to_i old_timeout = redis.getset( key, timeout_i( expiration ) ).to_i if old_timeout < Time.now.to_i return true end end end false end |
#has_redis_lock?(locked_key) ⇒ Boolean
100 101 102 |
# File 'lib/redis_support/locks.rb', line 100 def has_redis_lock?( locked_key ) redis.exists lock_key(locked_key) end |
#is_redis_fulfilling_locked?(locked_key) ⇒ Boolean
108 109 110 |
# File 'lib/redis_support/locks.rb', line 108 def is_redis_fulfilling_locked?( locked_key ) redis.get( locked_key ).to_i > Time.now.to_i end |
#is_redis_locked?(locked_key) ⇒ Boolean
104 105 106 |
# File 'lib/redis_support/locks.rb', line 104 def is_redis_locked?( locked_key ) locked_until(locked_key) > Time.now.to_i end |
#locked_until(locked_key) ⇒ Object
112 113 114 |
# File 'lib/redis_support/locks.rb', line 112 def locked_until(locked_key) redis.get( lock_key(locked_key) ).to_i end |
#redefine_redis_key(name, keystruct) ⇒ Object
70 71 72 73 74 75 76 77 78 79 |
# File 'lib/redis_support/class_extensions.rb', line 70 def redefine_redis_key( name, keystruct ) if Keys.methods.include? name.to_s Keys.class_eval <<-RUBY class << self undef #{name} end RUBY end redis_key(name, keystruct) end |
#redis ⇒ Object
13 14 15 16 17 18 19 |
# File 'lib/redis_support/class_extensions.rb', line 13 def redis if(self == RedisSupport) @redis else @redis || RedisSupport.redis end end |
#redis=(connection) ⇒ Object
9 10 11 |
# File 'lib/redis_support/class_extensions.rb', line 9 def redis=(connection) @redis = RedisSupport.redis_connect(connection) end |
#redis_key(name, keystruct) ⇒ Object
Goal is to allow a class to declare a redis key/property The key is a colon delimited string where variables are listed are upper case (underscores inbetween) and non variables are completely lower case (underscores inbetween or appending/prepending)
variables cannot be repeated and must start with a letter the key must also start with a nonvariable
Examples
redis_key :workpools, "job:JOB_ID:workpools"
Returns the redis key.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/redis_support/class_extensions.rb', line 34 def redis_key( name, keystruct ) if Keys.methods.include? name.to_s return # raise DuplicateRedisKeyDefinitionError end key = keystruct.split(":") unless (first = key.shift) =~ STR_PATTERN raise InvalidRedisKeyDefinitionError.new "keys must begin with lowercase letters" end vars, strs = key.inject([[],[]]) do |(vs, ss), token| case token when VAR_PATTERN var = token.downcase ss << "\#{#{var}}" vs << var when STR_PATTERN ss << token else raise InvalidRedisKeyDefinitionError.new "Internal error parsing #{keystruct} : last token : #{token}" end [vs, ss] end strs.unshift(first) RedisSupport::Keys.class_eval <<-RUBY, __FILE__, __LINE__ + 1 def self.#{name.to_s}( #{vars.map {|x| x.to_s }.join(', ')} ) "#{strs.join(":")}" end RUBY RedisSupport::Keys.keystructs << keystruct end |
#redis_lock(key_to_lock, expiration = 30, interval = 1) ⇒ Object
Lock a block of code so it can only be accessed by one thread in our system at a time.
See ‘acquire_redis_lock’ for details on parameters.
Returns nothing.
12 13 14 15 16 17 |
# File 'lib/redis_support/locks.rb', line 12 def redis_lock( key_to_lock, expiration = 30, interval = 1 ) acquire_redis_lock( key_to_lock, expiration, interval ) yield ensure release_redis_lock( key_to_lock ) end |
#redis_lock_nonblock(key_to_lock, expiration = 30) ⇒ Object
Attempt to lock a block of code so it can only be accessed by one thread in our system at a time. Skips the block if it cannot lock.
See ‘acquire_redis_lock_nonblock’ for details on parameters.
Returns nothing.
25 26 27 28 29 30 |
# File 'lib/redis_support/locks.rb', line 25 def redis_lock_nonblock( key_to_lock, expiration = 30 ) lock_acquired = acquire_redis_lock_nonblock( key_to_lock, expiration ) yield if lock_acquired ensure release_redis_lock( key_to_lock ) if lock_acquired end |
#redis_throttle(key_to_lock, expiration = 30) ⇒ Object
Throttle a block of code so it is only executed at most every ‘expiration` seconds. The block is skipped if it has been run more recently.
Returns nothing
37 38 39 |
# File 'lib/redis_support/locks.rb', line 37 def redis_throttle( key_to_lock, expiration = 30 ) yield if acquire_redis_lock_nonblock( key_to_lock, expiration ) end |
#release_redis_lock(locked_key) ⇒ Object
See docs for acquire_redis_lock above
Returns nothing.
96 97 98 |
# File 'lib/redis_support/locks.rb', line 96 def release_redis_lock( locked_key ) redis.del lock_key( locked_key ) end |