Skip to content

fix(sandbox): avoid session mirrors after sandbox release - #3039

Open
larry-zy wants to merge 6 commits into
agentscope-ai:mainfrom
larry-zy:fix/session-tree-sandbox-mirror-lifecycle
Open

fix(sandbox): avoid session mirrors after sandbox release#3039
larry-zy wants to merge 6 commits into
agentscope-ai:mainfrom
larry-zy:fix/session-tree-sandbox-mirror-lifecycle

Conversation

@larry-zy

@larry-zy larry-zy commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • skip best-effort SessionTree mirrors when their pinned sandbox has been released
  • report a clear sandbox exception when Kubernetes file transfer uses a closed connection
  • add regression coverage for both cases

Testing

  • mvn -pl agentscope-harness -am -DskipITs -Dtest=SessionTreeMirrorTest -Dsurefire.failIfNoSpecifiedTests=false test
  • mvn -pl agentscope-extensions/agentscope-extensions-sandbox/agentscope-extensions-sandbox-kubernetes -am -DskipTests package

Fixes #3036

@larry-zy larry-zy changed the title fix(harness): avoid session mirrors after sandbox release fix(sandbox): avoid session mirrors after sandbox release Sep 8, 2026
@codecov

codecov Bot commented Sep 8, 2026

Copy link
Copy Markdown

@oss-maintainer oss-maintainer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Summary

Guards the best-effort session mirror against races with self-managed sandbox release: a new static Sandbox → MirrorGate (ReentrantReadWriteLock) in PinnedSandboxFilesystem blocks release until in-flight uploads finish and rejects new ones afterwards, SandboxLifecycleMiddleware marks the gate before sandboxManager.release(...), SessionTree skips mirrors for a released sandbox, and ObjectStoreTranscriptStore.appendSegment / mirrorToFilesystem now fail loudly instead of ignoring a returned failure response. The problem is real (#3036) and the "stop reporting a mirror as done when the upload actually failed" part is a genuine improvement — compact() in particular was previously free to delete the input segments after a lost upload.

Findings

  • [Critical] PinnedSandboxFilesystem.java:81 — the read lock spans the whole remote upload while release takes the write lock, so call teardown now waits on an unbounded network transfer; one stalled upload hangs releaseForCall (and the lease close) on the agent's completion path.
  • [Warning] PinnedSandboxFilesystem.java:44released is a one-way latch keyed on the Sandbox instance with no reset path (resume/reconnect rebinds instances), and WeakHashMap key equality is not identity-based.
  • [Warning] SessionTree.java:745 — the new early return also skips the local index.upsertFromLocalFile, so a failed mirror leaves the workspace index stale for a file that exists on disk.
  • [Warning] ObjectStoreTranscriptStore.java:91appendSegment now throws, which scheduleSegmentMirror logs and compact() propagates; the interface documents no failure contract, and the "released" case becomes a WARN storm instead of a distinguishable skip.
  • [Warning] SessionTreeMirrorTest.java:213 — both new tests exercise isRunning() == false (the pre-existing liveness check); markSandboxReleased and the gate interaction are untested.
  • [Info] KubernetesSandbox.java:289 — solid addition; exec/persistWorkspace/hydrateWorkspace remain unguarded and WORKSPACE_STOP_ERROR is reused for a closed connection.

Suggestions

The blocking-teardown item is the one I'd like resolved before merge — a bounded tryLock on the gate keeps the intended ordering for new mirrors without letting an un-timed remote write stall call release. The rest are contract/test hardening: name the "skipped because released" outcome so callers can treat it as normal, state the throws contract on TranscriptStore#appendSegment, keep the local index update independent of the remote copy, and add one test that drives the gate itself.

Also related for the maintainer's eye: #3094 (defer self-managed sandbox shutdown via a retain/release counter) and #3106 (move transcript persistence off the completion path) are attacking the same lifecycle window from three directions with three different mechanisms — worth converging on one owner for "async write vs. sandbox release" before all three land.


Automated review by github-manager-bot

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

Labels

None yet

Projects

None yet

2 participants