Skip to content

Commit 6f7a603

Browse files
raagsjeffwidman
authored andcommitted
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.
1 parent 1119413 commit 6f7a603

2 files changed

Lines changed: 28 additions & 4 deletions

File tree

kazoo/recipe/lock.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,23 +126,33 @@ def cancel(self):
126126
self.cancelled = True
127127
self.wake_event.set()
128128

129-
def acquire(self, blocking=True, timeout=None):
129+
def acquire(self, blocking=True, timeout=None, ephemeral=True):
130130
"""
131131
Acquire the lock. By defaults blocks and waits forever.
132132
133133
:param blocking: Block until lock is obtained or return immediately.
134134
:type blocking: bool
135135
:param timeout: Don't wait forever to acquire the lock.
136136
:type timeout: float or None
137+
:param ephemeral: Don't use ephemeral znode for the lock.
138+
:type ephemeral: bool
137139
138140
:returns: Was the lock acquired?
139141
:rtype: bool
140142
141143
:raises: :exc:`~kazoo.exceptions.LockTimeout` if the lock
142144
wasn't acquired within `timeout` seconds.
143145
146+
.. warning::
147+
148+
When :attr:`ephemeral` is set to False session expiration
149+
will not release the lock and must be handled separately.
150+
144151
.. versionadded:: 1.1
145152
The timeout option.
153+
154+
.. versionadded:: 2.4.1
155+
The ephemeral option.
146156
"""
147157

148158
def _acquire_lock():
@@ -170,7 +180,8 @@ def _acquire_lock():
170180
gotten = False
171181
try:
172182
gotten = retry(self._inner_acquire,
173-
blocking=blocking, timeout=timeout)
183+
blocking=blocking, timeout=timeout,
184+
ephemeral=ephemeral)
174185
except RetryFailedError:
175186
pass
176187
except KazooException:
@@ -192,7 +203,7 @@ def _watch_session(self, state):
192203
self.wake_event.set()
193204
return True
194205

195-
def _inner_acquire(self, blocking, timeout):
206+
def _inner_acquire(self, blocking, timeout, ephemeral=True):
196207

197208
# wait until it's our chance to get it..
198209
if self.is_acquired:
@@ -212,7 +223,7 @@ def _inner_acquire(self, blocking, timeout):
212223

213224
if not node:
214225
node = self.client.create(self.create_path, self.data,
215-
ephemeral=True, sequence=True)
226+
ephemeral=ephemeral, sequence=True)
216227
# strip off path to node
217228
node = node[len(self.path) + 1:]
218229

kazoo/tests/test_lock.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from kazoo.exceptions import CancelledError
88
from kazoo.exceptions import LockTimeout
9+
from kazoo.exceptions import NoNodeError
910
from kazoo.testing import KazooTestCase
1011
from kazoo.tests import util as test_util
1112

@@ -355,6 +356,18 @@ def test_lock_reacquire(self):
355356
lock.acquire()
356357
lock.release()
357358

359+
def test_lock_ephemeral(self):
360+
client1 = self._get_client()
361+
client1.start()
362+
lock = client1.Lock(self.lockpath, "ephemeral")
363+
lock.acquire(ephemeral=False)
364+
znode = self.lockpath + '/' + lock.node
365+
client1.stop()
366+
try:
367+
self.client.get(znode)
368+
except NoNodeError:
369+
self.fail("NoNodeError raised unexpectedly!")
370+
358371
def test_lock_timeout(self):
359372
timeout = 3
360373
e = self.make_event()

0 commit comments

Comments
 (0)