From 185327f59cf213ed99ddc92f154be4f63f1db7ba Mon Sep 17 00:00:00 2001 From: Nick Elser Date: Mon, 13 Apr 2015 21:21:45 -0700 Subject: [PATCH] fix documentation and add another test for refresh --- README.md | 27 +++++++++++++++++++++++---- test/client_test.rb | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b436f95..c280eca 100644 --- a/README.md +++ b/README.md @@ -41,16 +41,35 @@ Thread.new { suo.lock("other_key", 2) { puts "Three" } } suo = Suo::Client::Memcached.new(client: some_dalli_client, acquisition_timeout: 1) # in seconds # manually locking/unlocking -suo.lock("a_key") +# the return value from lock without a block is a unique token valid only for the current lock +# which must be unlocked manually +lock = suo.lock("a_key") foo.baz! -suo.unlock("a_key") +suo.unlock("a_key", lock) -# custom stale lock cleanup (cleaning of dead clients) +# custom stale lock expiration (cleaning of dead locks) suo = Suo::Client::Redis.new(client: some_redis_client, stale_lock_expiration: 60*5) ``` +### Stale locks + +"Stale locks" - those acquired more than `stale_lock_expiration` (defaulting to 3600 or one hour) ago - are automatically cleared during any operation on the key (`lock`, `unlock`, `refresh`). The `locked?` method will not return true if only stale locks exist, but will not modify the key itself. + +To re-acquire a lock in the middle of a block, you can use the refresh method on client. + +```ruby +suo = Suo::Client::Redis.new + +# lock is the same token as seen in the manual example, above +suo.lock("foo") do |lock| + 5.times do + baz.bar! + suo.refresh("foo", lock) + end +end +``` + ## TODO - - better stale key handling (refresh blocks) - more race condition tests ## History diff --git a/test/client_test.rb b/test/client_test.rb index 2858bb6..478bc8d 100644 --- a/test/client_test.rb +++ b/test/client_test.rb @@ -191,6 +191,38 @@ module ClientTests end def test_refresh + client = client(stale_lock_expiration: 0.5) + + lock1 = client.lock(TEST_KEY) + + assert_equal true, client.locked?(TEST_KEY) + + client.refresh(TEST_KEY, lock1) + + assert_equal true, client.locked?(TEST_KEY) + + sleep 0.55 + + assert_equal false, client.locked?(TEST_KEY) + + lock2 = client.lock(TEST_KEY) + + client.refresh(TEST_KEY, lock1) + + assert_equal true, client.locked?(TEST_KEY) + + client.unlock(TEST_KEY, lock1) + + # edge case with refresh lock in the middle + assert_equal true, client.locked?(TEST_KEY) + + client.unlock(TEST_KEY, lock2) + + # now finally unlocked + assert_equal false, client.locked?(TEST_KEY) + end + + def test_block_refresh success_counter = Queue.new failure_counter = Queue.new