0

My question relates to Kazoo/Zookeeper, but more generally it's about allocating a resource and then letting the caller of that resource no they should pause. From Kazoo docs:

It’s highly recommended to add a state listener with add_listener() and watch for LOST and SUSPENDED state changes and re-act appropriately. In the event that a LOST state occurs, its certain that the lock and/or the lease has been lost.

I'm using a context manager to allocate locks:

@contextmanager
def lock(self, path, identifier):
  lock = zk.Lock(path, identifier)
  lock.acquire()
  yield lock      <--- how to communicate connection loss from client?
  finally: 
    lock.release()

Used like this:

with lock('/some_op/') as lck:
  # do something with lock, but pause in case of connection loss? 

How do you allocate a lock but revoke access in case of connection loss?

here's how Kazoo recommends you implement the connection state listener:

def my_listener(state):
    if state == KazooState.LOST:
        # Register somewhere that the session was lost
    elif state == KazooState.SUSPENDED:
        # Handle being disconnected from Zookeeper
    else:
        # Handle being connected/reconnected to Zookeeper
tgk
  • 3,857
  • 2
  • 27
  • 42

1 Answers1

1

This may not be the best design, but you can provide a reference to the lock to the body of the with statement:

@contextmanager
def acquire_lock(self, path, identifier):
  lock = zk.Lock(path, identifier)
  try: 
    retry = KazooRetry()
    retry(lock.acquire)
    yield lock
  finally: 
    lock.release()

with acquire_lock('/some_op/') as lock:
    ...
    if necessary:
        lock.release()
    ...

Specific to your question (I am not familiar with Kazoo), you can define my_listener inside the context manager, where it can close over the lock.

@contextmanager
def acquire_lock(self, path, identifier):
    lock = zk.Lock(path, identifier)
    def my_listener(state):
        if state == KazooState.LOST:
            lock.release()
        elif state == KazooState.SUSPENDED:
            ...

    try:
        retry = KazooRetry()
    # etc

Your context may need to yield the listener, or register it (or whatever you do with listeners) itself, but whatever you do with it, it will have access to the lock you created in the context manager.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • Thanks @chepner! the `if necessary` part is specifically what i'm trying to figure out how to pass down through the contextmanager. and the trouble with using the listener is that "calls can be made to Zookeeper from any callback except for a state listener without worrying that critical session events will be blocked" https://kazoo.readthedocs.io/en/latest/implementation.html?highlight=thread#handlers i guess the lock does have the client ... so I could inspect `lock.client.state` ... hmmm that may work – tgk May 29 '19 at 19:54