fix(compose): preserve container state across daemon restarts#72
Conversation
Shellout path: thread an `existingContainer` signal from `up.go` into `upComposeShellout` and append `--no-recreate` to `docker compose up` when a container is already known for this workspace. Matches the upstream devcontainers/cli gate (`container || expectExistingContainer`). Without the flag, compose's default recreate-on-drift behavior can destroy a perfectly-good container whenever it detects any change in the generated override files or in caller-injected env, taking the container's writable layer (e.g. `~/.claude/projects/...`) with it. Native orchestrator: when an existing container's config-hash and image-digest match but its state is not Running (e.g. dockerd was just restarted and brought stopped containers back from on-disk state), start it instead of stop+remove+recreating. Same root cause as the shellout flag gap — drop it now so it doesn't follow us to the native backend. Tests: - runtime/docker: `--no-recreate` is appended iff NoRecreate is set. - compose: a config-matched Exited container is reused via StartContainer with no RunContainer / RemoveContainer calls. Both tests fail against the prior code (verified by reverting each fix in isolation), so they would catch a future regression. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughThis PR fixes container state destruction across daemon restarts by preventing recreation when compose config hashes match. It adds a ChangesContainer preservation on compose refresh
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Closes #71.
Summary
existingContainerbool fromup.gothroughcreateFreshCompose→upComposeShellout→ComposeUpSpec.NoRecreate. When set,buildUpArgsappends--no-recreatetodocker compose up -d. Mirrors upstreamdevcontainers/cli's gate (container || expectExistingContainer).LabelConfigHashandLabelImageDigestmatch the desired spec but its state is notRunning,StartContainerit instead of stop+remove+recreate. The previous gate (c.State == runtime.StateRunningas a third reuse condition) destroyed perfectly-good containers any time dockerd had been restarted, because daemon-restored containers come backExited.Both branches share one root cause: drift in compose-side config-hash (or a temporarily-stopped container) was being treated as a recreate signal, which destroys the container's writable layer. For workspaces where
~/.claude,~/.bash_history, install caches, or anything else lives in$HOME, that's data loss.Test plan
go test ./...clean.TestBuildUpArgs_NoRecreate/TestBuildUpArgs_NoRecreateOmittedByDefaultcover the argv edges. Verified the positive case fails against the pre-fixbuildUpArgs.TestUp_StartsStoppedContainerOnConfigMatchsimulates a daemon-restart by stopping a previously-Up'd container and Up-ing again; asserts the container ID is preserved,StartContaineris called once, andRunContainer/RemoveContainerare not. Verified it fails against the pre-fix orchestrator.~/.claude/projects/<encoded>/<sid>.jsonlacross pod restart and Claude SDK errors with"No conversation found with session ID: <sid>". With this patch the JSONL survives.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
--no-recreateflag support to preserve existing containers when configuration changes.Tests
--no-recreateflag behavior.