Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added locking class

  • Loading branch information...
commit 9bbe06c664d733ed4aee9ef52ebef3850b8cf586 1 parent b8240a4
@tobi authored
Showing with 110 additions and 0 deletions.
  1. +43 −0 lock/lock.rb
  2. +67 −0 lock/test.rb
View
43 lock/lock.rb
@@ -0,0 +1,43 @@
+require 'rubygems'
+require 'redis'
+require 'digest/md5'
+require 'active_support'
+
+$redis = Redis.new
+
+class Lock
+ class Error < StandardError
+ end
+
+ def self.acquire(key, lock_time = 1.second)
+ start_time = Time.now.to_i
+ loop do
+ now = Time.now.to_i
+
+ if $redis.setnx(key, now + lock_time)
+ begin
+ yield
+ return
+ ensure
+ $redis.del(key)
+ end
+
+ else
+ time = $redis.get(key)
+ if time.to_i < now
+ if $redis.getset(key, now + lock_time) == time
+ $redis.del(key)
+ end
+ else
+
+ # Give up after 3x lock_time
+ if now > start_time + (lock_time * 3)
+ raise Error, 'could not aquire lock'
+ end
+ sleep 0.001
+ end
+ end
+ end
+ end
+end
+
View
67 lock/test.rb
@@ -0,0 +1,67 @@
+require "test/unit"
+
+require File.dirname(__FILE__) + "/lock"
+
+class TestLock < Test::Unit::TestCase
+ def setup
+ $redis.flushall
+ end
+
+ def test_lock
+ run = false
+ Lock.acquire 'a' do
+ run = true
+ end
+
+ assert run
+ end
+
+ def test_expired_lock_is_overtaken
+ $redis['a'] = 5.minutes.ago.to_i
+
+ run = false
+ Lock.acquire 'a' do
+ run = true
+ end
+ assert run
+ end
+
+ def test_cannot_get_lock
+
+ $redis['b'] = 5.minutes.from_now.to_i
+
+ assert_raise(Lock::Error) do
+ Lock.acquire 'b' do
+ raise 'should not happen'
+ end
+ end
+ end
+
+ def test_lock_exclusive_access
+
+ run = false
+
+ results = []
+
+ a = Thread.new do
+ Lock.acquire('a', 1.minute) do
+ sleep 5
+ results << 'first'
+ end
+ end
+
+ b = Thread.new do
+ sleep 1
+
+ Lock.acquire('a', 1.minute) do
+ results << 'second'
+ end
+
+ end
+
+
+ a.join; b.join
+
+ assert_equal ['first', 'second'], results
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.