11import logging
2+ import random
3+ import time
4+ from datetime import timedelta
25from typing import (
36 Annotated ,
47 Callable ,
1114
1215from .address_helper import validate_address
1316from .consumer import Consumer
14- from .entities import StreamOptions
17+ from .entities import RecoveryConfiguration , StreamOptions
1518from .exceptions import ArgumentOutOfRangeException
1619from .management import Management
1720from .publisher import Publisher
21+ from .qpid .proton ._exceptions import ConnectionException
1822from .qpid .proton ._handlers import MessagingHandler
1923from .qpid .proton ._transport import SSLDomain
2024from .qpid .proton .utils import BlockingConnection
@@ -53,7 +57,7 @@ def __init__(
5357 ssl_context : Union [
5458 PosixSslConfigurationContext , WinSslConfigurationContext , None
5559 ] = None ,
56- reconnect : bool = False ,
60+ recovery_configuration : Optional [ RecoveryConfiguration ] = None ,
5761 ):
5862 """
5963 Initialize a new Connection instance.
@@ -80,7 +84,7 @@ def __init__(
8084 PosixSslConfigurationContext , WinSslConfigurationContext , None
8185 ] = ssl_context
8286 self ._managements : list [Management ] = []
83- self ._reconnect = reconnect
87+ self ._recovery_configuration = recovery_configuration
8488 self ._ssl_domain = None
8589 self ._connections = [] # type: ignore
8690 self ._index : int = - 1
@@ -144,7 +148,10 @@ def dial(self) -> None:
144148 password ,
145149 )
146150
147- if self ._reconnect is False :
151+ if (
152+ self ._recovery_configuration is None
153+ or self ._recovery_configuration .active_recovery is False
154+ ):
148155 self ._conn = BlockingConnection (
149156 url = self ._addr ,
150157 urls = self ._addrs ,
@@ -274,26 +281,53 @@ def _on_disconnection(self) -> None:
274281 if self in self ._connections :
275282 self ._connections .remove (self )
276283
277- self ._conn = BlockingConnection (
278- url = self ._addr ,
279- urls = self ._addrs ,
280- ssl_domain = self ._ssl_domain ,
281- on_disconnection_handler = self ._on_disconnection ,
282- )
284+ base_delay = self ._recovery_configuration .back_off_reconnect_interval # type: ignore
285+ max_delay = timedelta (minutes = 1 )
286+
287+ for attempt in range (self ._recovery_configuration .MaxReconnectAttempts ): # type: ignore
288+
289+ jitter = timedelta (milliseconds = random .randint (0 , 500 ))
290+ delay = base_delay + jitter
291+
292+ if delay > max_delay :
293+ delay = max_delay
294+
295+ time .sleep (delay .total_seconds ())
283296
284- self ._connections .append (self )
297+ try :
298+ self ._conn = BlockingConnection (
299+ url = self ._addr ,
300+ urls = self ._addrs ,
301+ ssl_domain = self ._ssl_domain ,
302+ on_disconnection_handler = self ._on_disconnection ,
303+ )
304+
305+ self ._connections .append (self )
306+
307+ for i , management in enumerate (self ._managements ):
308+ # Update the broken connection and sender in the management
309+ self ._managements [i ]._update_connection (self ._conn )
285310
286- for i , management in enumerate (self ._managements ):
287- # Update the broken connection and sender in the management
288- self ._managements [i ]._update_connection (self ._conn )
311+ for i , publisher in enumerate (self ._publishers ):
312+ # Update the broken connection and sender in the publisher
313+ self ._publishers [i ]._update_connection (self ._conn )
289314
290- for i , publisher in enumerate (self ._publishers ):
291- # Update the broken connection and sender in the publisher
292- self ._publishers [i ]._update_connection (self ._conn )
315+ for i , consumer in enumerate (self ._consumers ):
316+ # Update the broken connection and sender in the consumer
317+ self ._consumers [i ]._update_connection (self ._conn )
318+
319+ except ConnectionException as e :
320+ base_delay *= 2
321+ logger .error (
322+ "Reconnection attempt failed" ,
323+ "attempt" ,
324+ attempt ,
325+ "error" ,
326+ str (e ),
327+ )
328+ continue
293329
294- for i , consumer in enumerate (self ._consumers ):
295- # Update the broken connection and sender in the consumer
296- self ._consumers [i ]._update_connection (self ._conn )
330+ break
297331
298332 @property
299333 def active_producers (self ) -> int :
0 commit comments