class ZookeeperServiceRegistry(BaseServiceRegistry): def __init__(self, hosts=DEFAULT_HOSTS, chroot=DEFAULT_CHROOT): super(ZookeeperServiceRegistry, self).__init__() self.chroot = chroot self.client = KazooClient( hosts=hosts, handler=SequentialGeventHandler(), ) self.client.add_listener(self.on_kazoo_state_change) self.start_count = 0 @classmethod def from_config(cls, config, **kwargs): return cls(hosts=config.get('hosts', DEFAULT_HOSTS), chroot=config.get('chroot', DEFAULT_CHROOT), **kwargs) def on_start(self, timeout=10): self.start_count += 1 if self.start_count > 1: return started = self.client.start_async() started.wait(timeout=timeout) if not self.client.connected: raise RuntimeError('could not connect to zookeeper') logger.debug('connected to zookeeper (version=%s)', '.'.join(map(str, self.client.server_version()))) def on_stop(self): self.start_count -= 1 if self.start_count != 0: return self.client.stop() def on_kazoo_state_change(self, state): logger.info('kazoo connection state changed to %s', state) def on_service_type_watch(self, service, event): try: if event.type == EventType.CHILD: # FIXME: figure out proper retry strategy self.client.retry(self.lookup, service.container, service) except Exception: logger.exception('error in service type watcher') def on_service_watch(self, service, event): try: prefix, service_type, identity = event.path.rsplit('/', 2) if event.type == EventType.DELETED: service.remove(identity) except Exception: logger.exception('error in service watcher') def _get_service_znode(self, service, service_type, identity): path = self._get_zk_path(service_type, identity) result = self.client.get_async(path, watch=functools.partial( self.on_service_watch, service)) value, znode = result.get() items = six.iteritems(json.loads(value.decode('utf-8'))) return {str(k): str(v) for k, v in items} def discover(self, container): result = self.client.get_children_async(path='%s/services' % self.chroot, ) return list(result.get()) def lookup(self, container, service, watch=True, timeout=1): def child_watch(event): print(event) service_type = service.service_type result = self.client.get_children_async( path='%s/services/%s' % (self.chroot, service_type), watch=functools.partial(self.on_service_type_watch, service), ) try: names = result.get(timeout=timeout) except NoNodeError: raise LookupFailure(None, "failed to resolve %s" % service.service_type) logger.info("lookup %s %r", service_type, names) identities = set(service.identities()) for name in names: kwargs = self._get_service_znode(service, service_type, name) identity = kwargs.pop('identity') service.update(identity, **kwargs) try: identities.remove(identity) except KeyError: pass for identity in identities: service.remove(identity) return service def _get_zk_path(self, service_type, identity): return '%s/services/%s/%s' % (self.chroot, service_type, identity) def register(self, container, service_type, timeout=1): path = self._get_zk_path(service_type, container.identity) value = json.dumps({ 'endpoint': container.endpoint, 'identity': container.identity, 'log_endpoint': container.log_endpoint, }) result = self.client.create_async(path, value.encode('utf-8'), ephemeral=True, makepath=True) # FIXME: result.set_exception(RegistrationFailure()) result.get(timeout=timeout) def unregister(self, container, service_type, timeout=1): path = self._get_zk_path(service_type, container.identity) result = self.client.delete_async(path) result.set_exception(RegistrationFailure()) result.get(timeout=timeout)
class ZookeeperServiceRegistry(BaseServiceRegistry): def __init__(self, hosts=DEFAULT_HOSTS, chroot=DEFAULT_CHROOT): super(ZookeeperServiceRegistry, self).__init__() self.chroot = chroot self.client = KazooClient( hosts=hosts, handler=SequentialGeventHandler(), ) self.client.add_listener(self.on_kazoo_state_change) self.start_count = 0 @classmethod def from_config(cls, config, **kwargs): return cls( hosts=config.get('hosts', DEFAULT_HOSTS), chroot=config.get('chroot', DEFAULT_CHROOT), **kwargs ) def on_start(self, timeout=10): self.start_count += 1 if self.start_count > 1: return started = self.client.start_async() started.wait(timeout=timeout) if not self.client.connected: raise RuntimeError('could not connect to zookeeper') logger.debug('connected to zookeeper (version=%s)', '.'.join(map(str, self.client.server_version()))) def on_stop(self): self.start_count -= 1 if self.start_count != 0: return self.client.stop() def on_kazoo_state_change(self, state): logger.info('kazoo connection state changed to %s', state) def on_service_type_watch(self, service, event): try: if event.type == EventType.CHILD: # FIXME: figure out proper retry strategy self.client.retry(self.lookup, service.container, service) except Exception: logger.exception('error in service type watcher') def on_service_watch(self, service, event): try: prefix, service_type, identity = event.path.rsplit('/', 2) if event.type == EventType.DELETED: service.remove(identity) except Exception: logger.exception('error in service watcher') def _get_service_znode(self, service, service_type, identity): path = self._get_zk_path(service_type, identity) result = self.client.get_async( path, watch=functools.partial(self.on_service_watch, service)) value, znode = result.get() items = six.iteritems(json.loads(value.decode('utf-8'))) return {str(k): str(v) for k, v in items} def discover(self, container): result = self.client.get_children_async( path='%s/services' % self.chroot, ) return list(result.get()) def lookup(self, container, service, watch=True, timeout=1): def child_watch(event): print(event) service_type = service.service_type result = self.client.get_children_async( path='%s/services/%s' % (self.chroot, service_type), watch=functools.partial(self.on_service_type_watch, service), ) try: names = result.get(timeout=timeout) except NoNodeError: raise LookupFailure(None, "failed to resolve %s" % service.service_type) logger.info("lookup %s %r", service_type, names) identities = set(service.identities()) for name in names: kwargs = self._get_service_znode(service, service_type, name) identity = kwargs.pop('identity') service.update(identity, **kwargs) try: identities.remove(identity) except KeyError: pass for identity in identities: service.remove(identity) return service def _get_zk_path(self, service_type, identity): return '%s/services/%s/%s' % (self.chroot, service_type, identity) def register(self, container, service_type, timeout=1): path = self._get_zk_path(service_type, container.identity) value = json.dumps({ 'endpoint': container.endpoint, 'identity': container.identity, 'log_endpoint': container.log_endpoint, }) result = self.client.create_async( path, value.encode('utf-8'), ephemeral=True, makepath=True) # FIXME: result.set_exception(RegistrationFailure()) result.get(timeout=timeout) def unregister(self, container, service_type, timeout=1): path = self._get_zk_path(service_type, container.identity) result = self.client.delete_async(path) result.set_exception(RegistrationFailure()) result.get(timeout=timeout)
class _ZookeeperProxy(object): def __init__(self, address_provider: AddressListProvider, prefix: str): self.address_provider = address_provider self.async_counter = WaitingCounter(limit=100) self.conn_str = None self.client = None self.prefix = prefix self.hosts_cache = SlowlyUpdatedCache( self.address_provider.get_latest_address, self._update_hosts, 30, # Refresh every 30 seconds 3 * 60) # Update only after 180 seconds of stability def _update_hosts(self, value): hosts, port = value if hosts: self.conn_str = ','.join(['{}:{}'.format(h, port) for h in hosts]) + self.prefix if self.client is None: self.client = KazooClient(hosts=self.conn_str, command_retry={ 'deadline': 120, 'max_delay': 1, 'max_tries': -1 }, connection_retry={ 'max_delay': 1, 'max_tries': -1 }) self.client.add_listener(self.session_listener) else: self.client.stop() self.client.set_hosts(self.conn_str) self.client.start() def terminate(self): if self.client: self.client.stop() def session_listener(self, state): pass def get_conn_str(self): return self.conn_str def get(self, *params): self.hosts_cache.touch() return self.client.retry(self.client.get, *params) def get_async(self, *params): # Exhibitor is not polled here and it's totally fine! self.async_counter.increment() try: i_async = self.client.get_async(*params) i_async.rawlink(self._decrement) return i_async except Exception as e: self._decrement() raise e def _decrement(self, *args, **kwargs): self.async_counter.decrement() def set(self, *args, **kwargs): self.hosts_cache.touch() return self.client.retry(self.client.set, *args, **kwargs) def create(self, *args, **kwargs): self.hosts_cache.touch() return self.client.retry(self.client.create, *args, **kwargs) def delete(self, *args, **kwargs): self.hosts_cache.touch() try: return self.client.retry(self.client.delete, *args, **kwargs) except NoNodeError: pass def get_children(self, *params): self.hosts_cache.touch() try: return self.client.retry(self.client.get_children, *params) except NoNodeError: return [] def take_lock(self, *args, **kwargs): while True: try: self.hosts_cache.touch() return self.client.Lock(*args, **kwargs) except Exception as e: _LOG.error('Failed to obtain lock for exhibitor, retrying', exc_info=e)
class Zookeeper: def __init__(self, hosts): self.zk = KazooClient(hosts=hosts, handler=SequentialGeventHandler(), logger=logger) # returns immediately event = self.zk.start_async() # Wait for 30 seconds and see if we're connected event.wait(timeout=30) try: if not self.zk.connected: # Not connected, stop trying to connect self.zk.stop() except (ConnectionLossException, NoAuthException) as error: raise error except Exception as error: raise error @coroutine def get_children(self, node): try: children = self.zk.get_children_async(node) raise Return(children.get()) except Exception as error: raise error @coroutine def get_node(self, node): try: data = self.zk.get_async(node) raise Return(data.get()) except Exception as error: raise error @coroutine def check_path_exist(self, path): try: result = self.zk.exists(path) if result: raise Return(True) else: raise Return(False) except Exception as error: raise error @coroutine def create_path(self, path): try: result = self.zk.ensure_path_async(path) raise Return(result.get()) except Exception as error: raise error @coroutine def create_node(self, path, value): try: result = self.zk.create_async(path=path, value=value, acl=None, ephemeral=True) raise Return(result.get()) except Exception as error: raise error @coroutine def update_node(self, path, value, version=-1): try: result = self.zk.set_async(path, value, version) raise Return(result.get()) except Exception as error: raise error @coroutine def update_node(self, path, value, version=-1): try: result = self.zk.set_async(path, value, version) raise Return(result.get()) except Exception as error: raise error @coroutine def del_node(self, node): try: node_info = self.zk.delete_async(node) raise Return(node_info.get()) except Exception as error: raise error def close(self): self.zk.stop()
class _ZookeeperProxy(object): def __init__(self, address_provider: AddressListProvider, prefix: str): self.address_provider = address_provider self.async_counter = WaitingCounter(limit=100) self.conn_str = None self.client = None self.prefix = prefix self.hosts_cache = SlowlyUpdatedCache( self.address_provider.get_latest_address, self._update_hosts, 30, # Refresh every 30 seconds 3 * 60) # Update only after 180 seconds of stability def _update_hosts(self, value): hosts, port = value if hosts: self.conn_str = ','.join(['{}:{}'.format(h, port) for h in hosts]) + self.prefix if self.client is None: self.client = KazooClient(hosts=self.conn_str, command_retry={'deadline': 120, 'max_delay': 1, 'max_tries': -1}, connection_retry={'max_delay': 1, 'max_tries': -1}) self.client.add_listener(self.session_listener) else: self.client.stop() self.client.set_hosts(self.conn_str) self.client.start() def terminate(self): if self.client: self.client.stop() def session_listener(self, state): pass def get_conn_str(self): return self.conn_str def get(self, *params): self.hosts_cache.touch() return self.client.retry(self.client.get, *params) def get_async(self, *params): # Exhibitor is not polled here and it's totally fine! self.async_counter.increment() try: i_async = self.client.get_async(*params) i_async.rawlink(self._decrement) return i_async except Exception as e: self._decrement() raise e def _decrement(self, *args, **kwargs): self.async_counter.decrement() def set(self, *args, **kwargs): self.hosts_cache.touch() return self.client.retry(self.client.set, *args, **kwargs) def create(self, *args, **kwargs): self.hosts_cache.touch() return self.client.retry(self.client.create, *args, **kwargs) def delete(self, *args, **kwargs): self.hosts_cache.touch() try: return self.client.retry(self.client.delete, *args, **kwargs) except NoNodeError: pass def get_children(self, *args, **kwargs): self.hosts_cache.touch() try: return self.client.retry(self.client.get_children, *args, **kwargs) except NoNodeError: return [] def take_lock(self, *args, **kwargs): while True: try: self.hosts_cache.touch() return self.client.Lock(*args, **kwargs) except Exception as e: _LOG.error('Failed to obtain lock for exhibitor, retrying', exc_info=e)
timeout=1, handler=SequentialGeventHandler()) event = zk.start_async() event.wait(timeout=1) # wait()方法等待start_async()返回的事件对象 if not zk.connected: # 由于可能永远连接失败,因此判断连接状态,做异常情况处理 zk.stop() raise Exception("Unable to connect") def my_callback(async_obj): try: print '-------------------------' children = async_obj.get() do_something(children) except (ConnectionLossException, NoAuthException): sys.exit(1) zk.create_async("/lws/test/1", b"test") data = zk.get_async("/lws/test/1") print data async_obj = zk.get_children_async("/lws/test/1") # print async_obj async_obj.rawlink(my_callback) # data = zk.exists_async("/lws/test/1") # print data