SIGN IN SIGN UP

fix: prevent StreamedLog stop() from hanging on a silent stream (#825)

## Summary

In `StreamedLog` (`src/apify_client/_streamed_log.py`), `stop()` sets
`_stop_logging = True` and then `join()`s the streaming thread. The
thread is parked inside `iter_bytes()` on a blocking socket read, so the
flag isn't observed until the next chunk arrives or the long-polling
server-side timeout (~360s) elapses — `stop()` can block for minutes on
a quiet actor.

Passing a `_read_timeout` (30s) to `_log_client.stream()` caps how long
`iter_bytes()` can block, so `stop()` unblocks within that window. The
timeout is exposed as a `ClassVar[timedelta]` so it can be tuned (or
shortened in tests) without monkeypatching a module global. The loop is
also wrapped in `try/finally` so the buffered tail is flushed even if a
read times out.

Tradeoff: the sync stream now ends if the actor goes silent for more
than 30s (vs. the prior 360s). This is documented on the class attribute
and is the intended cost of bounded `stop()`.

A regression test covers the bug.
V
Vlada Dusek committed
c15cb1bb2702120dd6fabe154a4b3d879248aafa
Parent: e794411
Committed by GitHub <noreply@github.com> on 5/26/2026, 6:41:59 AM