Skip to content

fix(sessions): stop a session pick from blocking command handling - #281

Open
atn18 wants to merge 1 commit into
grinev:mainfrom
atn18:fix/pick-outbound-drain
Open

atn18 wants to merge 1 commit into
grinev:mainfrom
atn18:fix/pick-outbound-drain

Conversation

@atn18

@atn18 atn18 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Description of changes

  • Picking a session in /sessions or /recent while it is still streaming kept the session-pick handler busy for the whole run: it held the aggregator's outbound queue, deferred one task per streaming delta, and replayed them one second apart inside the handler. grammY handles updates sequentially, so the whole update loop stayed blocked while the picked session streamed (observed as 10-13 minute stalls right after picking a busy session): every command, button press and message sent meanwhile waited, and messages older than 60 seconds were then dropped as stale with the "Telegram was unreachable" notice.
  • Deferred partial-text and thinking tasks now coalesce per message (last-wins), so a long stream keeps one task per message instead of one per delta.
  • The pick releases the hold in the background, tied to the hold generation it took: an older release never drains or clears a newer hold, a drain stops before the next task when a newer hold starts, and the lost-run ending keeps its completion barrier through the idle wait.

Closes issue (optional)

  • None

How it was tested

  • npm run lint, npm run build, npm run typecheck, npm test - all green (2823 passed, 7 skipped).
  • New tests: deferred partial and thinking tasks coalesce and keep their order; a stale generation cannot drain a newer hold; a caller whose generation went stale while it awaited the drain returns without touching the newer hold; a delta that replaces the head during the gap runs the latest payload once; a running drain stops when a newer hold starts during the gap and leaves the queue to it; the idle barrier resolves only after the queue drains; a payload arriving mid-drain is delivered; the ending releases its hold when it throws, and a throwing pre-drain check still drains the pick hold.
  • Handler test with the real background task: a pick resolves while the drain is still pending, the release passes the pick's hold generation, and a deferred task is drained in the background afterwards.
  • Lost-run test: the ending stays pending when a newer hold takes over the queue and resolves once that hold drains it.

Checklist

  • PR title follows Conventional Commits: <type>(<scope>)?: <description>
  • This PR contains one logically complete change
  • Branch is rebased on the latest main
  • I ran npm run lint, npm run build, and npm test
  • If this PR is OS-sensitive, behavior/limitations for Linux/macOS/Windows are described

@atn18
atn18 marked this pull request as draft October 21, 2026 08:07
@atn18
atn18 force-pushed the fix/pick-outbound-drain branch 3 times, most recently from 9ca39ce to 3aa860d Compare October 21, 2026 11:20
@atn18
atn18 marked this pull request as ready for review October 21, 2026 12:04
Picking a session held the aggregator's outbound queue, deferred one task
per streaming delta and replayed them at a one-second gap inside grammY's
sequential update loop, so commands sent while the picked session kept
streaming waited until the run ended and were then dropped as stale with
the outage notice.

Coalesce deferred partial-text and thinking tasks per message (last-wins)
and run the pick's drain in the background, tied to its hold generation so
an older release never drains a newer hold. The lost-run ending keeps its
completion barrier through the idle wait.
@atn18
atn18 force-pushed the fix/pick-outbound-drain branch from 3aa860d to 78393bd Compare October 22, 2026 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant