@@ -101,40 +101,28 @@ def _do_resolve(host: str, port: int) -> List[_AddrInfo]:
101101 return []
102102
103103
104- class AbstractEtcdClientWithFailover ( abc . ABC , etcd . Client ):
104+ class StaleEtcdNodeGuard ( object ):
105105
106- ERROR_CLS : Type [Exception ]
106+ def __init__ (self ) -> None :
107+ self ._reset_cluster_raft_term ()
107108
108- def __init__ (self , config : Dict [ str , Any ], dns_resolver : DnsCachingResolver , cache_ttl : int = 300 ) -> None :
109+ def _reset_cluster_raft_term (self ) -> None :
109110 self ._cluster_id = None
110111 self ._raft_term = 0
111- self ._dns_resolver = dns_resolver
112- self .set_machines_cache_ttl (cache_ttl )
113- self ._machines_cache_updated = 0
114- kwargs = {p : config .get (p ) for p in ('host' , 'port' , 'protocol' , 'use_proxies' , 'version_prefix' ,
115- 'username' , 'password' , 'cert' , 'ca_cert' ) if config .get (p )}
116- super (AbstractEtcdClientWithFailover , self ).__init__ (read_timeout = config ['retry_timeout' ], ** kwargs )
117- # For some reason python3-etcd on debian and ubuntu are not based on the latest version
118- # Workaround for the case when https://github.com/jplana/python-etcd/pull/196 is not applied
119- self .http .connection_pool_kw .pop ('ssl_version' , None )
120- self ._config = config
121- self ._load_machines_cache ()
122- self ._allow_reconnect = True
123- # allow passing retry argument to api_execute in params
124- self ._comparison_conditions .add ('retry' )
125- self ._read_options .add ('retry' )
126- self ._del_conditions .add ('retry' )
127112
128113 def _check_cluster_raft_term (self , cluster_id : Optional [str ], value : Union [None , str , int ]) -> None :
129114 """Check that observed Raft Term in Etcd cluster is increasing.
130115
131- If we observe that the new value is smaller than the previously known one, it could be an
132- indicator that we connected to a stale node and should switch to some other node.
133- However, we need to reset the memorized value when we notice that Cluster ID changed.
116+ :param cluster_id: last observed Etcd Cluster ID
117+ :param raft_term: last observed Raft Term
118+
119+ :raises:
120+ :exc::`StaleEtcdNode` if last observed *raft_term* is smaller than previously known *raft_term*.
134121 """
135122 if not (cluster_id and value ):
136123 return
137124
125+ # We need to reset the memorized value when we notice that Cluster ID changed.
138126 if self ._cluster_id and self ._cluster_id != cluster_id :
139127 logger .warning ('Etcd Cluster ID changed from %s to %s' , self ._cluster_id , cluster_id )
140128 self ._raft_term = 0
@@ -151,6 +139,30 @@ def _check_cluster_raft_term(self, cluster_id: Optional[str], value: Union[None,
151139 raise StaleEtcdNode
152140 self ._raft_term = raft_term
153141
142+
143+ class AbstractEtcdClientWithFailover (abc .ABC , etcd .Client , StaleEtcdNodeGuard ):
144+
145+ ERROR_CLS : Type [Exception ]
146+
147+ def __init__ (self , config : Dict [str , Any ], dns_resolver : DnsCachingResolver , cache_ttl : int = 300 ) -> None :
148+ StaleEtcdNodeGuard .__init__ (self )
149+ self ._dns_resolver = dns_resolver
150+ self .set_machines_cache_ttl (cache_ttl )
151+ self ._machines_cache_updated = 0
152+ kwargs = {p : config .get (p ) for p in ('host' , 'port' , 'protocol' , 'use_proxies' , 'version_prefix' ,
153+ 'username' , 'password' , 'cert' , 'ca_cert' ) if config .get (p )}
154+ super (AbstractEtcdClientWithFailover , self ).__init__ (read_timeout = config ['retry_timeout' ], ** kwargs )
155+ # For some reason python3-etcd on debian and ubuntu are not based on the latest version
156+ # Workaround for the case when https://github.com/jplana/python-etcd/pull/196 is not applied
157+ self .http .connection_pool_kw .pop ('ssl_version' , None )
158+ self ._config = config
159+ self ._load_machines_cache ()
160+ self ._allow_reconnect = True
161+ # allow passing retry argument to api_execute in params
162+ self ._comparison_conditions .add ('retry' )
163+ self ._read_options .add ('retry' )
164+ self ._del_conditions .add ('retry' )
165+
154166 def _calculate_timeouts (self , etcd_nodes : int , timeout : Optional [float ] = None ) -> Tuple [int , float , int ]:
155167 """Calculate a request timeout and number of retries per single etcd node.
156168 In case if the timeout per node is too small (less than one second) we will reduce the number of nodes.
0 commit comments