fix(server): Address premature provider reaping by treating provider runtime output as session activity#3856
fix(server): Address premature provider reaping by treating provider runtime output as session activity#3856ozppupbg wants to merge 2 commits into
Conversation
Change activity tracking to cover provider side, not only user actions. This keeps the provider session active while (sub)agents are running. Partially addresses pingdotgg#2980 & pingdotgg#2378. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughProvider session runtimes can now update ChangesProvider session activity tracking
Sequence Diagram(s)sequenceDiagram
participant RuntimeEvent
participant ProviderService
participant ProviderSessionDirectory
participant ProviderSessionRuntimeRepository
RuntimeEvent->>ProviderService: processRuntimeEvent(canonicalEvent)
ProviderService->>ProviderService: publish event and increment metrics
ProviderService->>ProviderSessionDirectory: touch(threadId) for allowed events
ProviderSessionDirectory->>ProviderSessionRuntimeRepository: update last-seen timestamp
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9e5c444. Configure here.
ApprovabilityVerdict: Needs human review This change alters session reaping behavior by treating provider runtime events as activity signals, which affects how long sessions stay alive. Changes to resource lifecycle management warrant human review. You can customize Macroscope's approvability policy. Learn more. |
…still unwinds; only a genuine touch failure is swallowed. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
@coderabbitai review |
✅ Action performedReview finished.
|

What Changed
Change activity tracking to cover provider side, not only user actions. This keeps the provider session active while (sub)agents are running.
Partially addresses #2980 & #2378..
Why
Long running (sub)agent activity can get truncated (and lost) when the idle-session reaper kills the session due to missing user activity (see #2980 & #2378).
Rather than extending the idle-session timeout (or making it configurable), the root cause from my perspective was, that only user actions are counted as session activity, and not model (or provider outputs).
Therefore, this patch changes the session tracking to include provider actions, while ensuring that frequent events don't overwhelm the database.
Detailed Changes described by Opus
The idle-session reaper (ProviderSessionReaper) kills sessions whose
lastSeenAt is older than the inactivity threshold (~30min). lastSeenAt was only
bumped on user-initiated actions (sendTurn, interruptTurn, binding
upserts), so a long-running turn with no fresh user input was treated as
idle and reaped mid-generation — dropping provider-side context even
though the model was actively working.
Bump lastSeenAt on every inbound runtime event in the central dispatcher
(ProviderService.processRuntimeEvent), which all provider runtimes
(Codex, Claude, OpenCode, Cursor, Grok) already flow through. Only
session.exited is excluded, so a terminated process can still be reaped.
Add ProviderSessionDirectory.touch() backed by a dedicated
touchByThreadId repository method: a single UPDATE of last_seen_at with
no preceding SELECT or JSON re-encoding, cheap enough to run per event.
Touch failures are logged at debug and swallowed so a transient DB error
never tears down the event subscription.
Checklist
Note
Medium Risk
Changes idle-session reaper inputs by updating
last_seen_aton every runtime event; incorrect deny-list or touch behavior could keep dead sessions alive or add DB write load.Overview
Provider runtime output now counts as session activity so long-running turns are not reaped while the model is still emitting events.
Adds
touchByThreadIdonProviderSessionRuntimeRepository(singleUPDATEoflast_seen_at, no full upsert) andProviderSessionDirectory.touch. InProviderService.processRuntimeEvent, after publishing each canonical runtime event, the service callstouchexcept forsession.exited, which is excluded so dead sessions can still be reaped. Touch failures are logged at debug and do not break the event pipeline; interrupts propagate.Reviewed by Cursor Bugbot for commit bd8a0a9. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix premature provider session reaping by treating runtime output events as session activity
touchon the session'slast_seen_attimestamp, preventing the session reaper from killing active provider sessions that haven't received explicit user input.touchByThreadIdtoProviderSessionRuntimeRepository, issuing anUPDATE provider_session_runtime SET last_seen_at = $1 WHERE thread_id = $2.touch(threadId)toProviderSessionDirectory, settinglast_seen_atto the current time.ProviderService,processRuntimeEventcallsbumpSessionActivityafter publishing each event, skippingsession.exitedevents; touch failures are logged at debug level unless the fiber is interrupted.Macroscope summarized bd8a0a9.
Summary by CodeRabbit
New Features
Bug Fixes