Fixes a correctness bug in the async streaming composition operators: their producer tasks could outlive or starve their consumer, spinning indefinitely (runaway CPU, unbounded memory, and — on constrained/CI hosts — preventing the process from exiting).
Fixed
- Streaming producer-task lifecycle in
merge,combineLatest,withLatestFrom,sample,debounce,timeout, andAsyncAlignedSequence:- Producer is cancelled when the consumer stops (
onTermination → producer.cancel()). - Producer loops break when
yieldreturns.terminated(consumer gone) — a reliable stop signal. mergeproducersawait Task.yield()per element so a non-suspending source can't monopolize the cooperative pool and starve the consumer.
- Producer is cancelled when the consumer stops (
Root-caused via a live sample() of the process hanging at exit on the macos-26 CI runner (all tests passed, then the process couldn't terminate).
Changed
- CI workflow: fixed YAML indentation, added
timeout-minutesand a hang-diagnostic watchdog. - De-flaked three pre-existing scheduler-dependent tests; raised over-tight hang-guard time limits.
🤖 Generated with Claude Code