Skip to content

Commit 1f248b2

Browse files
committed
Add unit test
1 parent aea32cc commit 1f248b2

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

ld_eventsource/sse_client.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def __init__(
111111

112112
self.__connection_client = connect.create_client(logger)
113113
self.__connection_result: Optional[ConnectionResult] = None
114-
self.__retry_reset_baseline: float = 0
114+
self._retry_reset_baseline: float = 0
115115
self.__disconnected_time: float = 0
116116

117117
self.__closed = False
@@ -253,12 +253,12 @@ def _compute_next_retry_delay(self):
253253
# In those situations, we don't want to reset the retry delay strategy;
254254
# it should continue to double until the retry maximum, and then hold
255255
# steady (- jitter).
256-
if self.__retry_delay_reset_threshold > 0 and self.__retry_reset_baseline != 0:
256+
if self.__retry_delay_reset_threshold > 0 and self._retry_reset_baseline != 0:
257257
now = time.time()
258-
connection_duration = now - self.__retry_reset_baseline
258+
connection_duration = now - self._retry_reset_baseline
259259
if connection_duration >= self.__retry_delay_reset_threshold:
260260
self.__current_retry_delay_strategy = self.__base_retry_delay_strategy
261-
self.__retry_reset_baseline = now
261+
self._retry_reset_baseline = now
262262
self.__next_retry_delay, self.__current_retry_delay_strategy = (
263263
self.__current_retry_delay_strategy.apply(self.__base_retry_delay)
264264
)
@@ -294,7 +294,7 @@ def _try_start(self, can_return_fault: bool) -> Optional[Fault]:
294294
# If can_return_fault is false, it means the caller explicitly called start(), in
295295
# which case there's no way to return a Fault so we just keep retrying transparently.
296296
continue
297-
self.__retry_reset_baseline = time.time()
297+
self._retry_reset_baseline = time.time()
298298
self.__current_error_strategy = self.__base_error_strategy
299299
self.__interrupted = False
300300
return None

ld_eventsource/testing/test_sse_client_retry.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from ld_eventsource.actions import *
33
from ld_eventsource.config import *
44
from ld_eventsource.testing.helpers import *
5+
from time import sleep
56

67

78
def test_retry_during_initial_connect_succeeds():
@@ -101,6 +102,57 @@ def test_all_iterator_continues_after_retry():
101102
assert client.next_retry_delay == initial_delay * 2
102103

103104

105+
def test_retry_delay_gets_reset_after_threshold():
106+
initial_delay = 0.005
107+
retry_delay_reset_threshold = 0.1
108+
mock = MockConnectStrategy(
109+
RespondWithData("data: data1\n\n"),
110+
RejectConnection(HTTPStatusError(503)),
111+
)
112+
with SSEClient(
113+
connect=mock,
114+
error_strategy=ErrorStrategy.always_continue(),
115+
initial_retry_delay=initial_delay,
116+
retry_delay_reset_threshold=retry_delay_reset_threshold,
117+
retry_delay_strategy=RetryDelayStrategy.default(jitter_multiplier=None),
118+
) as client:
119+
assert client._retry_reset_baseline == 0
120+
all = client.all
121+
122+
# Establish a successful connection
123+
item1 = next(all)
124+
assert isinstance(item1, Start)
125+
assert client._retry_reset_baseline != 0
126+
127+
item2 = next(all)
128+
assert isinstance(item2, Event)
129+
assert item2.data == 'data1'
130+
131+
# Stream is dropped and then fails to re-connect, resulting in backoff.
132+
item3 = next(all)
133+
assert isinstance(item3, Fault)
134+
assert client.next_retry_delay == initial_delay
135+
136+
item4 = next(all)
137+
assert isinstance(item4, Fault)
138+
assert client.next_retry_delay == initial_delay * 2
139+
140+
# Sleeping the threshold should reset the retry thresholds
141+
sleep(retry_delay_reset_threshold)
142+
143+
# Which we see it does here
144+
item5 = next(all)
145+
assert isinstance(item5, Fault)
146+
assert client.next_retry_delay == initial_delay
147+
148+
# And if we don't sleep long enough, it doesn't get reset.
149+
sleep(retry_delay_reset_threshold / 2)
150+
151+
item6 = next(all)
152+
assert isinstance(item6, Fault)
153+
assert client.next_retry_delay == initial_delay * 2
154+
155+
104156
def test_can_interrupt_and_restart_stream():
105157
initial_delay = 0.005
106158
mock = MockConnectStrategy(

0 commit comments

Comments
 (0)