summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaghu Udiyar <raghusiddarth@gmail.com>2018-01-15 00:12:43 +0530
committerJeff Widman <jeff@jeffwidman.com>2018-03-23 13:44:15 -0700
commit6f7a603de9f04ec46d9946c6f5b1cb6e2b913b63 (patch)
treeb21652ca8b029882328ed725972a0c739244568d
parent111941371daec00a2ecb5d8c29b9b1d35d6aa4ff (diff)
downloadkazoo-6f7a603de9f04ec46d9946c6f5b1cb6e2b913b63.tar.gz
feat(recipe): allow non ephemeral locking
Right now if the program taking the lock exits, the lock is also released implicitly as the zk node is ephemeral. In some usecases its desirable to make the lock release explicit. For example, in scripting multiple programs that contend for a lock, or purposeful failing lock acquirers to detect issues. The ephemeral flag in acquire() allows for this behavior.
-rw-r--r--kazoo/recipe/lock.py19
-rw-r--r--kazoo/tests/test_lock.py13
2 files changed, 28 insertions, 4 deletions
diff --git a/kazoo/recipe/lock.py b/kazoo/recipe/lock.py
index 95a8272..6a50cfb 100644
--- a/kazoo/recipe/lock.py
+++ b/kazoo/recipe/lock.py
@@ -126,7 +126,7 @@ class Lock(object):
self.cancelled = True
self.wake_event.set()
- def acquire(self, blocking=True, timeout=None):
+ def acquire(self, blocking=True, timeout=None, ephemeral=True):
"""
Acquire the lock. By defaults blocks and waits forever.
@@ -134,6 +134,8 @@ class Lock(object):
:type blocking: bool
:param timeout: Don't wait forever to acquire the lock.
:type timeout: float or None
+ :param ephemeral: Don't use ephemeral znode for the lock.
+ :type ephemeral: bool
:returns: Was the lock acquired?
:rtype: bool
@@ -141,8 +143,16 @@ class Lock(object):
:raises: :exc:`~kazoo.exceptions.LockTimeout` if the lock
wasn't acquired within `timeout` seconds.
+ .. warning::
+
+ When :attr:`ephemeral` is set to False session expiration
+ will not release the lock and must be handled separately.
+
.. versionadded:: 1.1
The timeout option.
+
+ .. versionadded:: 2.4.1
+ The ephemeral option.
"""
def _acquire_lock():
@@ -170,7 +180,8 @@ class Lock(object):
gotten = False
try:
gotten = retry(self._inner_acquire,
- blocking=blocking, timeout=timeout)
+ blocking=blocking, timeout=timeout,
+ ephemeral=ephemeral)
except RetryFailedError:
pass
except KazooException:
@@ -192,7 +203,7 @@ class Lock(object):
self.wake_event.set()
return True
- def _inner_acquire(self, blocking, timeout):
+ def _inner_acquire(self, blocking, timeout, ephemeral=True):
# wait until it's our chance to get it..
if self.is_acquired:
@@ -212,7 +223,7 @@ class Lock(object):
if not node:
node = self.client.create(self.create_path, self.data,
- ephemeral=True, sequence=True)
+ ephemeral=ephemeral, sequence=True)
# strip off path to node
node = node[len(self.path) + 1:]
diff --git a/kazoo/tests/test_lock.py b/kazoo/tests/test_lock.py
index cae4837..ae907ed 100644
--- a/kazoo/tests/test_lock.py
+++ b/kazoo/tests/test_lock.py
@@ -6,6 +6,7 @@ from nose.tools import eq_, ok_
from kazoo.exceptions import CancelledError
from kazoo.exceptions import LockTimeout
+from kazoo.exceptions import NoNodeError
from kazoo.testing import KazooTestCase
from kazoo.tests import util as test_util
@@ -355,6 +356,18 @@ class KazooLockTests(KazooTestCase):
lock.acquire()
lock.release()
+ def test_lock_ephemeral(self):
+ client1 = self._get_client()
+ client1.start()
+ lock = client1.Lock(self.lockpath, "ephemeral")
+ lock.acquire(ephemeral=False)
+ znode = self.lockpath + '/' + lock.node
+ client1.stop()
+ try:
+ self.client.get(znode)
+ except NoNodeError:
+ self.fail("NoNodeError raised unexpectedly!")
+
def test_lock_timeout(self):
timeout = 3
e = self.make_event()