v37.2
sipcapture/homerv37.2Aug 6, 2026by pierre-b
AI Summary
Fixes critical reliability issues in broadcast execution, ensuring tasks run within their own deadlines and preventing broadcasts from being stranded or killed unexpectedly.
Key Highlights
- Broadcasts no longer die when the triggering connection goes away
- Retry budget resets on pause instead of being a lifetime budget
- Failed batch enqueues are retried from the same cursor
- Interrupted broadcasts are now paused with a reason instead of being stranded
Breaking Changes
- API endpoint behavior change: `GET /api/cron` now returns `202 Accepted` immediately instead of blocking the caller
Full Release Notes
- **Improvement**: A broadcast no longer dies when the connection that triggered it goes away. Task execution ran on the triggering HTTP request's context, so the dispatcher's own 53s client timeout — only 3s above a 50s broadcast slice — cancelled the run mid-batch, aborting the enqueue transaction and surfacing as `sql: transaction has already been committed or rolled back` followed by a misleading `[BROADCAST_NOT_FOUND] ... context canceled`. Execution is now bounded by the task's own deadline instead of the caller's connection, and each dispatch waits for as long as its task may legitimately run rather than a fixed 53s (which also silently truncated the 300s segment-recompute tasks). - **Improvement**: `max_retries` is now a consecutive-failure budget instead of a lifetime one. It was never reset, and *pausing* a broadcast counted as a failed attempt, so three pause/resume cycles — or three transient failures hours apart during a long send — permanently killed a broadcast. A run interrupted by a restart or a hung-up caller no longer consumes the budget at all, and resuming a broadcast clears it. - **Improvement**: A failed batch enqueue no longer skips recipients. The sender reported the whole batch as processed even though its single transaction had written nothing, so the orchestrator advanced past those contacts and they were never mailed — with every enqueue failing, a broadcast would march through its entire audience and still report itself as sent. The batch is now retried from the same cursor. - **Improvement**: A broadcast interrupted past its retry limit is now paused with a reason, and resumable from where it stopped, instead of being stranded. The write that finalised its status ran on the very context whose cancellation caused the failure, so it silently did nothing and left the broadcast stuck in "sending" for good with its task dead. - **Improvement**: An A/B test whose first sending run was cut short — a transient database error, a restart — could then send the **entire audience** as a single blast with variations mixed, instead of only the test sample, and leave the broadcast stuck in "testing" with no way forward. The run that opens a test phase records the phase in the task's state, but a failed run saves no state, and the next run had no way to recover the phase from the broadcast's own status. - **Change**: `GET /api/cron` returns `202 Accepted` immediately instead of holding the caller open for the whole run, restoring the behaviour external cron setups relied on before in-process execution landed. A caller that gives up no longer cancels the tasks it started, and overlapping triggers are ignored while a run is in flight.