Skip to content

Commit ada05e4

Browse files
committed
fix: timeouts
1 parent 8c4266b commit ada05e4

2 files changed

Lines changed: 29 additions & 22 deletions

File tree

replane/_async.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ async def connect(self, *, wait: bool = True) -> None:
171171

172172
logger.debug("connect() called, wait=%s", wait)
173173

174+
# Use request_timeout for the handshake (server should respond quickly).
175+
# read=None means no read timeout (for SSE streaming).
174176
self._http_client = httpx.AsyncClient(
175177
timeout=httpx.Timeout(self._request_timeout, read=None),
176178
)
@@ -340,7 +342,11 @@ async def __aexit__(self, *args: Any) -> None:
340342
await self.close()
341343

342344
async def _run_stream(self) -> None:
343-
"""Background task that maintains the SSE connection."""
345+
"""Background task that maintains the SSE connection.
346+
347+
During initialization: retries until init succeeds or wait_for_init times out.
348+
After initialization: retries indefinitely until close() is called.
349+
"""
344350
retry_count = 0
345351
max_retries = 10
346352

@@ -350,21 +356,20 @@ async def _run_stream(self) -> None:
350356
retry_count = 0
351357
except asyncio.CancelledError:
352358
break
353-
except ReplaneError as e:
359+
except AuthenticationError as e:
360+
# Auth errors are permanent - don't retry
354361
if not self._initialized.is_set():
355362
self._init_error = e
356363
self._initialized.set()
357-
return
364+
return
358365

366+
except ReplaneError as e:
367+
# During init: log and retry (wait_for_init will timeout if needed)
368+
# After init: log and retry indefinitely
359369
logger.warning("SSE connection error: %s", e)
360370

361371
except Exception as e:
362372
error = NetworkError(str(e), cause=e)
363-
if not self._initialized.is_set():
364-
self._init_error = error
365-
self._initialized.set()
366-
return
367-
368373
logger.warning("SSE connection error: %s", error)
369374

370375
if self._closed:

replane/_sync.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -314,29 +314,32 @@ def __exit__(self, *args: Any) -> None:
314314
self.close()
315315

316316
def _run_stream(self) -> None:
317-
"""Background thread that maintains the SSE connection."""
317+
"""Background thread that maintains the SSE connection.
318+
319+
During initialization: retries until init succeeds or wait_for_init times out.
320+
After initialization: retries indefinitely until close() is called.
321+
"""
318322
retry_count = 0
319323
max_retries = 10
320324

321325
while not self._stop_event.is_set():
322326
try:
323327
self._connect_stream()
324328
retry_count = 0 # Reset on successful connection
325-
except ReplaneError as e:
329+
except AuthenticationError as e:
330+
# Auth errors are permanent - don't retry
326331
if not self._initialized.is_set():
327332
self._init_error = e
328333
self._initialized.set()
329-
return
334+
return
330335

336+
except ReplaneError as e:
337+
# During init: log and retry (wait_for_init will timeout if needed)
338+
# After init: log and retry indefinitely
331339
logger.warning("SSE connection error: %s", e)
332340

333341
except Exception as e:
334342
error = NetworkError(str(e), cause=e)
335-
if not self._initialized.is_set():
336-
self._init_error = error
337-
self._initialized.set()
338-
return
339-
340343
logger.warning("SSE connection error: %s", error)
341344

342345
if self._stop_event.is_set():
@@ -366,24 +369,23 @@ def _connect_stream(self) -> None:
366369
is_https,
367370
)
368371

369-
# Create connection
370-
# Note: SSE connections are long-lived, so we use the inactivity timeout
371-
# rather than the short request timeout. The inactivity timeout is used
372-
# for detecting dead connections during streaming.
372+
# Use request_timeout for the initial handshake (server should respond
373+
# with headers within this time). After headers are received, we set
374+
# the socket timeout to inactivity_timeout for streaming.
373375
conn: http.client.HTTPConnection
374376
if is_https:
375377
context = ssl.create_default_context()
376378
conn = http.client.HTTPSConnection(
377379
host,
378380
port,
379-
timeout=self._inactivity_timeout,
381+
timeout=self._request_timeout,
380382
context=context,
381383
)
382384
else:
383385
conn = http.client.HTTPConnection(
384386
host,
385387
port,
386-
timeout=self._inactivity_timeout,
388+
timeout=self._request_timeout,
387389
)
388390

389391
try:

0 commit comments

Comments
 (0)