fix(sandbox/v2): LifecycleAction uses computer.BoxID instead of cfg.ID
cfg (ast.SandboxV2) is a pointer shared across all concurrent calls to the same Assistant. GetComputer writes cfg.ID = <random hex> for each oneshot request, so concurrent tasks overwrite each other's ID. When cleanup runs in defer, cfg.ID holds whichever task last wrote it — not the ID of the box this request created — so manager.Remove/Heartbeat silently fails with "sandbox: not found" and the container leaks. Fix: derive the box ID from computer.ComputerInfo().BoxID, which is the immutable b.id set at Create time and never mutated by concurrent callers. Made-with: Cursor
This commit is contained in:
parent
c26d764857
commit
cc0bb7e161
1 changed files with 9 additions and 3 deletions
|
|
@ -284,24 +284,30 @@ func resolveBox(
|
||||||
|
|
||||||
// LifecycleAction performs the post-request lifecycle operation based on policy.
|
// LifecycleAction performs the post-request lifecycle operation based on policy.
|
||||||
// Called in defer after executeSandboxStream completes.
|
// Called in defer after executeSandboxStream completes.
|
||||||
|
//
|
||||||
|
// NOTE: cfg.ID must NOT be used here — it is a shared mutable field on the
|
||||||
|
// Assistant struct and is overwritten by concurrent requests. The authoritative
|
||||||
|
// box ID is computer.ComputerInfo().BoxID, which is set once when the Box is
|
||||||
|
// created and never changes.
|
||||||
func LifecycleAction(ctx context.Context, cfg *types.SandboxConfig, computer infra.Computer, manager *infra.Manager) {
|
func LifecycleAction(ctx context.Context, cfg *types.SandboxConfig, computer infra.Computer, manager *infra.Manager) {
|
||||||
if computer == nil || cfg == nil {
|
if computer == nil || cfg == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
info := computer.ComputerInfo()
|
info := computer.ComputerInfo()
|
||||||
|
boxID := info.BoxID // use the box's own immutable ID, not cfg.ID
|
||||||
|
|
||||||
switch cfg.Lifecycle {
|
switch cfg.Lifecycle {
|
||||||
case "oneshot":
|
case "oneshot":
|
||||||
if info.Kind == "box" && manager != nil {
|
if info.Kind == "box" && manager != nil {
|
||||||
if err := manager.Remove(ctx, cfg.ID); err != nil {
|
if err := manager.Remove(ctx, boxID); err != nil {
|
||||||
log.Trace("[sandbox/v2] oneshot remove %s: %v", cfg.ID, err)
|
log.Trace("[sandbox/v2] oneshot remove %s: %v", boxID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "session", "longrunning":
|
case "session", "longrunning":
|
||||||
if info.Kind == "box" && manager != nil {
|
if info.Kind == "box" && manager != nil {
|
||||||
manager.Heartbeat(cfg.ID, false, 0) // active=false: request finished, start idle timer
|
manager.Heartbeat(boxID, false, 0) // active=false: request finished, start idle timer
|
||||||
}
|
}
|
||||||
|
|
||||||
case "persistent":
|
case "persistent":
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue