Skip to content

fix(server): Address premature provider reaping by treating provider runtime output as session activity#3856

Open
ozppupbg wants to merge 2 commits into
pingdotgg:mainfrom
ozppupbg:2980-patch
Open

fix(server): Address premature provider reaping by treating provider runtime output as session activity#3856
ozppupbg wants to merge 2 commits into
pingdotgg:mainfrom
ozppupbg:2980-patch

Conversation

@ozppupbg

@ozppupbg ozppupbg commented Jul 10, 2026

Copy link
Copy Markdown

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

  • This PR is small and focused
  • I explained what changed and why
  • Change has been running cleanly without issues for me for a couple of days

Note

Medium Risk
Changes idle-session reaper inputs by updating last_seen_at on 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 touchByThreadId on ProviderSessionRuntimeRepository (single UPDATE of last_seen_at, no full upsert) and ProviderSessionDirectory.touch. In ProviderService.processRuntimeEvent, after publishing each canonical runtime event, the service calls touch except for session.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

  • Provider runtime events now trigger a touch on the session's last_seen_at timestamp, preventing the session reaper from killing active provider sessions that haven't received explicit user input.
  • Adds touchByThreadId to ProviderSessionRuntimeRepository, issuing an UPDATE provider_session_runtime SET last_seen_at = $1 WHERE thread_id = $2.
  • Adds touch(threadId) to ProviderSessionDirectory, setting last_seen_at to the current time.
  • In ProviderService, processRuntimeEvent calls bumpSessionActivity after publishing each event, skipping session.exited events; touch failures are logged at debug level unless the fiber is interrupted.

Macroscope summarized bd8a0a9.

Summary by CodeRabbit

  • New Features

    • Session activity is now refreshed automatically when eligible provider runtime events occur.
    • Added support for updating a session’s last-seen timestamp without replacing the existing session record.
  • Bug Fixes

    • Excluded session exit events from extending session activity.
    • Improved handling and logging of session activity update failures.

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>
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a0b5dbf0-00ee-4412-87a0-79a137491f67

📥 Commits

Reviewing files that changed from the base of the PR and between f61fa94 and bd8a0a9.

📒 Files selected for processing (6)
  • apps/server/src/persistence/ProviderSessionRuntime.ts
  • apps/server/src/provider/Layers/CodexAdapter.test.ts
  • apps/server/src/provider/Layers/OpenCodeAdapter.test.ts
  • apps/server/src/provider/Layers/ProviderService.ts
  • apps/server/src/provider/Layers/ProviderSessionDirectory.ts
  • apps/server/src/provider/Services/ProviderSessionDirectory.ts

📝 Walkthrough

Walkthrough

Provider session runtimes can now update last_seen_at through a directory touch operation. Eligible runtime events trigger this update, while denied event types are excluded and touch failures receive dedicated handling.

Changes

Provider session activity tracking

Layer / File(s) Summary
Runtime timestamp persistence
apps/server/src/persistence/ProviderSessionRuntime.ts
Adds the touch input, repository method, SQL update, and service wiring for updating last_seen_at by thread ID.
Session directory touch operation
apps/server/src/provider/Services/ProviderSessionDirectory.ts, apps/server/src/provider/Layers/ProviderSessionDirectory.ts, apps/server/src/provider/Layers/CodexAdapter.test.ts, apps/server/src/provider/Layers/OpenCodeAdapter.test.ts
Adds touch(threadId), timestamps calls, maps persistence errors, and updates adapter test doubles.
Runtime event activity integration
apps/server/src/provider/Layers/ProviderService.ts
Touches allowed runtime sessions after event publication and metric updates, excludes session.exited, and handles touch failures.
Estimated code review effort: 3 (Moderate) ~20 minutes

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
Loading

Poem

I’m a rabbit with timestamps bright,
Touching sessions through the night.
Events hop, old exits stay,
Last-seen fields update away.
Thump thump! The runtime’s in sight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: provider runtime events now count as session activity to prevent premature reaping.
Description check ✅ Passed The description includes the required What Changed and Why sections, plus a checklist, and it is detailed enough for this template.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 10, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ 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.

Comment thread apps/server/src/provider/Layers/ProviderService.ts
Comment thread apps/server/src/provider/Layers/ProviderService.ts
@macroscopeapp

macroscopeapp Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: 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>
@ozppupbg

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant