|
|
-
Re: gevent, python and zookeeper.Ben Bangert 2012-05-25, 17:33
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", "192.168.0.122:6380") > 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 get_children. 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 |