|
25 | 25 | from kazoo.protocol.connection import ConnectionHandler
|
26 | 26 | from kazoo.protocol.paths import _prefix_root, normpath
|
27 | 27 | from kazoo.protocol.serialization import (
|
| 28 | + AddWatch, |
28 | 29 | Auth,
|
29 | 30 | CheckVersion,
|
30 | 31 | CloseInstance,
|
|
38 | 39 | SetACL,
|
39 | 40 | GetData,
|
40 | 41 | Reconfig,
|
| 42 | + RemoveWatches, |
41 | 43 | SetData,
|
42 | 44 | Sync,
|
43 | 45 | Transaction,
|
|
48 | 50 | KazooState,
|
49 | 51 | KeeperState,
|
50 | 52 | WatchedEvent,
|
| 53 | + AddWatchMode, |
| 54 | + WatcherType, |
51 | 55 | )
|
52 | 56 | from kazoo.retry import KazooRetry
|
53 | 57 | from kazoo.security import ACL, OPEN_ACL_UNSAFE
|
@@ -248,6 +252,8 @@ def __init__(
|
248 | 252 | self.state_listeners = set()
|
249 | 253 | self._child_watchers = defaultdict(set)
|
250 | 254 | self._data_watchers = defaultdict(set)
|
| 255 | + self._persistent_watchers = defaultdict(set) |
| 256 | + self._persistent_recursive_watchers = defaultdict(set) |
251 | 257 | self._reset()
|
252 | 258 | self.read_only = read_only
|
253 | 259 |
|
@@ -416,8 +422,16 @@ def _reset_watchers(self):
|
416 | 422 | for data_watchers in self._data_watchers.values():
|
417 | 423 | watchers.extend(data_watchers)
|
418 | 424 |
|
| 425 | + for persistent_watchers in self._persistent_watchers.values(): |
| 426 | + watchers.extend(persistent_watchers) |
| 427 | + |
| 428 | + for pr_watchers in self._persistent_recursive_watchers.values(): |
| 429 | + watchers.extend(pr_watchers) |
| 430 | + |
419 | 431 | self._child_watchers = defaultdict(set)
|
420 | 432 | self._data_watchers = defaultdict(set)
|
| 433 | + self._persistent_watchers = defaultdict(set) |
| 434 | + self._persistent_recursive_watchers = defaultdict(set) |
421 | 435 |
|
422 | 436 | ev = WatchedEvent(EventType.NONE, self._state, None)
|
423 | 437 | for watch in watchers:
|
@@ -1644,8 +1658,111 @@ def reconfig_async(self, joining, leaving, new_members, from_config):
|
1644 | 1658 |
|
1645 | 1659 | return async_result
|
1646 | 1660 |
|
| 1661 | + def add_watch(self, path, watch, mode): |
| 1662 | + """Add a watch. |
| 1663 | +
|
| 1664 | + This method adds persistent watches. Unlike the data and |
| 1665 | + child watches which may be set by calls to |
| 1666 | + :meth:`KazooClient.exists`, :meth:`KazooClient.get`, and |
| 1667 | + :meth:`KazooClient.get_children`, persistent watches are not |
| 1668 | + removed after being triggered. |
| 1669 | +
|
| 1670 | + To remove a persistent watch, use |
| 1671 | + :meth:`KazooClient.remove_all_watches` with an argument of |
| 1672 | + :attr:`~kazoo.protocol.states.WatcherType.ANY`. |
| 1673 | +
|
| 1674 | + The `mode` argument determines whether or not the watch is |
| 1675 | + recursive. To set a persistent watch, use |
| 1676 | + :class:`~kazoo.protocol.states.AddWatchMode.PERSISTENT`. To set a |
| 1677 | + persistent recursive watch, use |
| 1678 | + :class:`~kazoo.protocol.states.AddWatchMode.PERSISTENT_RECURSIVE`. |
| 1679 | +
|
| 1680 | + :param path: Path of node to watch. |
| 1681 | + :param watch: Watch callback to set for future changes |
| 1682 | + to this path. |
| 1683 | + :param mode: The mode to use. |
| 1684 | + :type mode: int |
| 1685 | +
|
| 1686 | + :raises: |
| 1687 | + :exc:`~kazoo.exceptions.MarshallingError` if mode is |
| 1688 | + unknown. |
| 1689 | +
|
| 1690 | + :exc:`~kazoo.exceptions.ZookeeperError` if the server |
| 1691 | + returns a non-zero error code. |
| 1692 | + """ |
| 1693 | + return self.add_watch_async(path, watch, mode).get() |
| 1694 | + |
| 1695 | + def add_watch_async(self, path, watch, mode): |
| 1696 | + """Asynchronously add a watch. Takes the same arguments as |
| 1697 | + :meth:`add_watch`. |
| 1698 | + """ |
| 1699 | + if not isinstance(path, str): |
| 1700 | + raise TypeError("Invalid type for 'path' (string expected)") |
| 1701 | + if not callable(watch): |
| 1702 | + raise TypeError("Invalid type for 'watch' (must be a callable)") |
| 1703 | + if not isinstance(mode, int): |
| 1704 | + raise TypeError("Invalid type for 'mode' (int expected)") |
| 1705 | + if mode not in ( |
| 1706 | + AddWatchMode.PERSISTENT, |
| 1707 | + AddWatchMode.PERSISTENT_RECURSIVE, |
| 1708 | + ): |
| 1709 | + raise ValueError("Invalid value for 'mode'") |
| 1710 | + |
| 1711 | + async_result = self.handler.async_result() |
| 1712 | + self._call( |
| 1713 | + AddWatch(_prefix_root(self.chroot, path), watch, mode), |
| 1714 | + async_result, |
| 1715 | + ) |
| 1716 | + return async_result |
| 1717 | + |
| 1718 | + def remove_all_watches(self, path, watcher_type): |
| 1719 | + """Remove watches from a path. |
| 1720 | +
|
| 1721 | + This removes all watches of a specified type (data, child, |
| 1722 | + any) from a given path. |
| 1723 | +
|
| 1724 | + The `watcher_type` argument specifies which type to use. It |
| 1725 | + may be one of: |
| 1726 | +
|
| 1727 | + * :attr:`~kazoo.protocol.states.WatcherType.DATA` |
| 1728 | + * :attr:`~kazoo.protocol.states.WatcherType.CHILDREN` |
| 1729 | + * :attr:`~kazoo.protocol.states.WatcherType.ANY` |
| 1730 | +
|
| 1731 | + To remove persistent watches, specify a watcher type of |
| 1732 | + :attr:`~kazoo.protocol.states.WatcherType.ANY`. |
| 1733 | +
|
| 1734 | + :param path: Path of watch to remove. |
| 1735 | + :param watcher_type: The type of watch to remove. |
| 1736 | + :type watcher_type: int |
| 1737 | + """ |
| 1738 | + |
| 1739 | + return self.remove_all_watches_async(path, watcher_type).get() |
| 1740 | + |
| 1741 | + def remove_all_watches_async(self, path, watcher_type): |
| 1742 | + """Asynchronously remove watches. Takes the same arguments as |
| 1743 | + :meth:`remove_all_watches`. |
| 1744 | + """ |
| 1745 | + if not isinstance(path, str): |
| 1746 | + raise TypeError("Invalid type for 'path' (string expected)") |
| 1747 | + if not isinstance(watcher_type, int): |
| 1748 | + raise TypeError("Invalid type for 'watcher_type' (int expected)") |
| 1749 | + if watcher_type not in ( |
| 1750 | + WatcherType.ANY, |
| 1751 | + WatcherType.CHILDREN, |
| 1752 | + WatcherType.DATA, |
| 1753 | + ): |
| 1754 | + raise ValueError("Invalid value for 'watcher_type'") |
| 1755 | + |
| 1756 | + async_result = self.handler.async_result() |
| 1757 | + self._call( |
| 1758 | + RemoveWatches(_prefix_root(self.chroot, path), watcher_type), |
| 1759 | + async_result, |
| 1760 | + ) |
| 1761 | + return async_result |
| 1762 | + |
1647 | 1763 |
|
1648 | 1764 | class TransactionRequest(object):
|
| 1765 | + |
1649 | 1766 | """A Zookeeper Transaction Request
|
1650 | 1767 |
|
1651 | 1768 | A Transaction provides a builder object that can be used to
|
|
0 commit comments