File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 33import asyncio
44
55from dqliteclient .connection import DqliteConnection
6- from dqliteclient .exceptions import ClusterError
6+ from dqliteclient .exceptions import ClusterError , DqliteConnectionError , OperationalError
77from dqliteclient .node_store import MemoryNodeStore , NodeInfo , NodeStore
88from dqliteclient .protocol import DqliteProtocol
99from dqliteclient .retry import retry_with_backoff
@@ -102,7 +102,17 @@ async def try_connect() -> DqliteConnection:
102102 await conn .connect ()
103103 return conn
104104
105- return await retry_with_backoff (try_connect , max_attempts = 5 )
105+ return await retry_with_backoff (
106+ try_connect ,
107+ max_attempts = 5 ,
108+ retryable_exceptions = (
109+ DqliteConnectionError ,
110+ ClusterError ,
111+ OperationalError ,
112+ OSError ,
113+ TimeoutError ,
114+ ),
115+ )
106116
107117 async def update_nodes (self , nodes : list [NodeInfo ]) -> None :
108118 """Update the node store with new node information."""
Original file line number Diff line number Diff line change @@ -11,6 +11,7 @@ async def retry_with_backoff[T](
1111 base_delay : float = 0.1 ,
1212 max_delay : float = 10.0 ,
1313 jitter : float = 0.1 ,
14+ retryable_exceptions : tuple [type [Exception ], ...] = (Exception ,),
1415) -> T :
1516 """Retry an async function with exponential backoff.
1617
@@ -20,12 +21,14 @@ async def retry_with_backoff[T](
2021 base_delay: Initial delay between retries in seconds
2122 max_delay: Maximum delay between retries
2223 jitter: Random jitter factor (0-1)
24+ retryable_exceptions: Exception types to retry on
2325
2426 Returns:
2527 Result of the function
2628
2729 Raises:
28- The last exception if all attempts fail
30+ The last exception if all attempts fail, or immediately
31+ for non-retryable exceptions
2932 """
3033 if max_attempts < 1 :
3134 raise ValueError ("max_attempts must be at least 1" )
@@ -35,7 +38,7 @@ async def retry_with_backoff[T](
3538 for attempt in range (max_attempts ):
3639 try :
3740 return await func ()
38- except Exception as e :
41+ except retryable_exceptions as e :
3942 last_error = e
4043
4144 if attempt == max_attempts - 1 :
Original file line number Diff line number Diff line change @@ -52,6 +52,24 @@ async def should_not_be_called() -> str:
5252 with pytest .raises (ValueError , match = "max_attempts must be at least 1" ):
5353 await retry_with_backoff (should_not_be_called , max_attempts = 0 )
5454
55+ async def test_non_retryable_exception_fails_immediately (self ) -> None :
56+ call_count = 0
57+
58+ async def raise_type_error () -> str :
59+ nonlocal call_count
60+ call_count += 1
61+ raise TypeError ("bug" )
62+
63+ with pytest .raises (TypeError , match = "bug" ):
64+ await retry_with_backoff (
65+ raise_type_error ,
66+ max_attempts = 5 ,
67+ base_delay = 0.01 ,
68+ retryable_exceptions = (ValueError ,),
69+ )
70+
71+ assert call_count == 1 # Should not retry
72+
5573 async def test_respects_max_delay (self ) -> None :
5674 import time
5775
You can’t perform that action at this time.
0 commit comments