Skip to content

fix(core): bound consumed job results - #47030

Merged
jlongster merged 1 commit into
v2from
consumed-job-cache
Sep 18, 2026
Merged

jlongster merged 1 commit into
v2from
consumed-job-cache

Conversation

@jlongster

@jlongster jlongster commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Bound the process-global Job service's consumed terminal history to 25 entries, instead of keeping every completed shell/subagent job for the server's lifetime. Evict the whole record so its output, metadata, and completed Deferred snapshots can be collected.

This is a separate alternative to #46087, not stacked on it. The overlap was identified during implementation and the requester explicitly preferred a separate PR. This variant uses a smaller, count-only cache ordered by first consumption, removes acknowledged background records immediately, and keeps the patch limited to production code. It does not implement a UTF-8 output-byte budget.

Retention policy

  • Keep running jobs and unconsumed terminal results: a job can finish before its caller gets from start() to block() / wait().
  • A terminal foreground block(), explicit cancel(), or non-recoverable wait() makes a job eligible for the 25-entry history. Repeated reads do not refresh its position.
  • Recoverable wait() alone does not consume the result, preserving the existing wait → background handoff, including immediately failed work.
  • Pending notification IDs protect results from history eviction. completeBackground() removes the durable marker and the matching terminal in-memory record under the registry lock.
  • Cleanup uses the existing generation token and notification ID, so an old observer/acknowledgment does not consume or remove a newer job with the same ID.
  • Existing waiters retain their generation's Deferred/results. Future lookups of evicted history use the existing missing-result shapes.

No tool, public HTTP/protocol, database schema, configuration, or installed-binary changes. The separate Shell cache and transcript/output handling are unchanged.

Scope of the bound: this is a history-entry bound, not a hard cap on total Job or server memory. Running work, unconsumed handoffs, pending notifications, caller-held results, and the size of individual result/metadata objects are outside the 25-entry bound. A producer that never consumes its result still owns that handoff.

Evidence

An isolated installed opencode2 v0.0.0-dev-18911 shell-tool probe observed 32 completed Job records after warm-up, 132 after 100 further commands, and the same 132 after idle GC. All job scopes were closed; each record still referenced a fixture-tagged output node, while the separate Shell cache stayed at 25 entries. Session message history stayed empty.

Those are pre-fix installed-server measurements, not a before/after memory claim for this patch. Bun's exported Map edges are incomplete, as documented in the report. Raw snapshots remain private.

Validation

  • OpenCode Drive completed 40 concurrent mixed shell jobs, including normal output, nonzero exit, timeout, and 200 KB output cases; the Session continued after history eviction.
  • The same Drive run completed a foreground subagent, a background shell notification, an interrupted shell, and a post-interruption shell recovery.
  • Existing Job suite: 15 passed.
  • Core bun typecheck, targeted Oxlint, both Effect AST rule sets, Prettier, and git diff --check passed.

@jlongster
jlongster merged commit 278db30 into v2 Sep 18, 2026
10 checks passed
@jlongster
jlongster deleted the consumed-job-cache branch September 18, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant