feat(task-dispatcher): idle-backoff / self-suspend the board poller (#4090)#4481
Conversation
…inyhumansai#4090) The board poller swept every board on a fixed 60s interval forever, even when the board was idle tick after tick — the diminishing-returns loop issue tinyhumansai#4090 describes. Thread a "did-work" signal up from `poll_board` / `poll_once` (true = dispatched a card) and drive an exponential backoff: after a short grace window of idle ticks the interval doubles up to a 15-minute ceiling (an effective self-suspend), and any dispatch resets it to the 60s base cadence. The capped ceiling still rechecks periodically so newly-arrived work is picked up without an unbounded stall. `next_poll_delay(idle_ticks)` is a pure, unit-tested backoff curve (base within the grace window; exponential past it; saturating at the ceiling, monotonic, overflow-safe). An event-driven instant wake on board mutation is a follow-up. Closes tinyhumansai#4090. Claude-Session: https://claude.ai/code/session_01KcmdqJVpjmnH31HqTHRLwG
Unrelated CI unblock (tinyhumansai#4446 golden drift; same fix as tinyhumansai#4475). Claude-Session: https://claude.ai/code/session_01KcmdqJVpjmnH31HqTHRLwG
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 49 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d8b95246c8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| .any(|c| c.status == TaskCardStatus::InProgress) | ||
| { | ||
| return Ok(()); | ||
| return Ok(false); |
There was a problem hiding this comment.
Keep polling at base cadence while a card is in progress
When a board has an InProgress card, this now reports an idle tick to the outer backoff loop. Since task completion only writes the card status back and there is no event-driven wake for the poller, a long-running task can push idle_ticks to the 15-minute cap; if other todo/ready cards are queued, and the running card finishes just after a sweep, the next card may not dispatch for up to 15 minutes instead of the previous 60 seconds. Treat an in-progress board as busy/non-idle or keep a shorter cadence while it can unblock queued work.
Useful? React with 👍 / 👎.
Summary
poll_board/poll_onceto drive it.next_poll_delay(idle_ticks)is a pure, unit-tested backoff curve.config_*_privacy_modeto a stale schema-catalog golden — see## Related.Problem
Issue #4090: long-running monitor/poll loops don't self-suspend on diminishing returns — they keep working every tick even when nothing changes. The concrete in-repo loop is the board poller (
task_dispatcher/poller.rs), which swept every board on a fixed 60sintervalforever, whether or not there was anything to dispatch.Solution
poll_board/poll_oncenow returntruewhen a card was dispatched (real work) andfalsewhen the board was idle (nothing to claim / no capacity).idle_tickscounter and sleepsnext_poll_delay(idle_ticks)before each sweep: base cadence within a small grace window, then exponential backoff (double per extra idle tick) saturating at a 15-minute ceiling. A dispatch resetsidle_ticksto 0 → immediate return to the 60s cadence.next_poll_delayis pure and deterministic (no timer), so the whole backoff curve is unit-tested: base within the grace window, exponential past it, monotonic non-decreasing, overflow-safe, and saturating at the ceiling.Submission Checklist
next_poll_delay_holds_base_cadence_within_the_grace_window,next_poll_delay_backs_off_exponentially_past_the_grace_window,next_poll_delay_saturates_at_the_ceiling(the edge: overflow/u32::MAXand the monotonic-≤-ceiling invariant).did-workthreading is a small return-value change on already-covered sweep paths.N/A: behaviour change to an existing internal loop.## Related— N/A.N/A: background poller cadence.Closes #NNN.Impact
Related
test(ci):change adds the privacy_mode methods to theworker_a_controller_schemas_are_fully_exposedgolden (pre-existing feat(privacy): Privacy Mode + local-only inference enforcement (#4435) #4446 break; also fixed in feat(orchestration): nested contacts → sessions with create + session send #4475). Note: this branch's E2E/coverage jobs are blocked by the feat(agent): tinyagents 1.5 migration wave — vendored SDK, dual-write sessions, goals/todos shadows, journals, middleware dedupe #4473 no-progress-nudge regression until [Harness] Change strategy after repeated unproductive results instead of retrying #4089's fix lands; will go green on rebase.AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
fix/GH-4090-poller-idle-backoffValidation Run
pnpm --filter openhuman-app format:check— N/A (no frontend changes)pnpm typecheck— N/A (no TS changes)openhuman::agent::task_dispatcher::poller::tests(the threenext_poll_delaycases) — execution deferred to CI (shared build host)rustfmt --edition 2021 --checkclean;cargo check --bin openhuman-corepassedValidation Blocked
command:cargo test --lib -- openhuman::agent::task_dispatcher::poller::testserror:none — shared build host saturatedimpact:cargo checkcompiled clean; the backoff curve is a pure deterministic function validated by CIBehavior Changes
Parity Contract
Duplicate / Superseded PR Handling