zookeeper-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ben Bangert <...@groovie.org>
Subject Re: gevent, python and zookeeper.
Date Fri, 25 May 2012 17:33:49 GMT
On 5/25/12 6:43 AM, Loki Davison wrote:
> I'm attempting to use zookeeper basically as a name server and to a
> lesser extent as a lock server. However I'm having trouble getting any
> of the python bindings to work with gevent and do what i require. I
> first implemented everything using zktools and zc.zk, which looked
> well documented and thought out and it all works well with threads but
> breaks with gevent. I'm not sure how to implement the solution from
> resumelb with monkey patch all (which i need to do for redis). I've
> tried to use kazoo but the watches are only fired once. If I attempt
> to reregister the watcher in the call back it block and never returns.
> I suspect i'm doing something incorrectly with kazoo. Has anyone
> successfully used watches with kazoo or can suggest a solution? The
> use case in question is a failover connection pool for redis, that
> also does leader election (redis has a single master), the code is on
> github using zktools:
> https://github.com/loki42/failover_connection
> Kazoo test case:
> import kazoo
> a = kazoo.KazooClient("localhost:2181")
> a.connect()
> import kazoo.recipe.party as party
> p = party.ZooParty(a, "/redis/providers", "")
> p.join()
> p.get_participant_count()
> def w_b(e):
>     print "### watcher called"
>     ## a.get_children("/redis/providers", w_b) ## explodes if i try
> this, otherwise called once.
>     return True
> a.get_children("/redis/providers", w_b)

So, here's whats going on from the code. Kazoo uses the async API for
all method calls under the hood. A single greenlet runs both watch
callbacks and completion callbacks. This means that when your watch
function is called, no completion callbacks can execute because the
watch function is blocking the only greenlet that handles *all*
callbacks including the completion one that is used to get the result of

The best way to handle this would be to actually spawn a greenlet from
the callback greenlet, so your w_b should look like this:

import gevent

def w_b(event):
    def watcher(e):
        print "### watcher called"
        a.get_children("/redis/providers", w_b)
        return True
    gevent.spawn(watcher, event)

a.get_children("/redis/providers", w_b)

This way the w_b func returns immediately and is no longer blocking the
watcher/completion greenlet so that ZK calls can return. As I merge the
code into the new kazoo I think it might be useful to have a separate
greenlet handle completion callbacks vs. watch callbacks so that
spawning new greenlets isn't needed just for a ZK call to complete.

Ben Bangert
(ben@ || http://) groovie.org

View raw message