fix network recreate#1416
Conversation
|
Warning Review limit reached
Next review available in: 42 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
/run-security-scan |
alexcos20
left a comment
There was a problem hiding this comment.
AI automated code review (Gemini 3).
Overall risk: low
Summary:
This PR effectively addresses the Docker network leak issue caused by node crashes mid-start. The self-healing implementation properly removes network instances by both their deterministic name and stored ID, ensuring robust cleanup. Code structure, error handling, and test coverage are excellent.
Comments:
• [INFO][style] Extracting isBenignDockerError to a higher scope is a great refactoring move. It avoids re-defining it inside stopService and ensures consistent error checking across different methods like removeServiceNetwork.
• [INFO][other] Excellent handling of the edge case where a container might be removed by an external process between network.inspect() and the .remove({ force: true }) call. Leveraging isBenignDockerError guarantees teardown stability.
• [INFO][bug] The self-healing logic here effectively catches the 409 conflict and properly recreates the network without halting the process. Well implemented.
• [INFO][other] Great addition of unit tests to mock and assert network operations. The testing of both leak scenarios and non-benign error propagation provides solid assurance for this fix. LGTM!
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai full review |
✅ Action performedFull review finished. Your plan includes PR reviews subject to rate limits. More reviews will be available in 42 minutes. |
Closing #1415
Fix: service restart wedged by leaked Docker network (409 "network already exists")
Restarting a Service-on-Demand job could fail permanently with
(HTTP code 409) unexpected - network with name ocean-svc-<serviceId> already exists,leaving the job stuck in
Error(99) with emptycontainerId/networkId— and everysubsequent restart failing the same way, with no way out short of manual
docker network rmon the host.
Root cause
Each service gets a Docker network with a deterministic name (
ocean-svc-<serviceId>),but every cleanup path (restart teardown, stop, orphan recovery, expiry sweep) removed it
only via the persisted
job.networkIdfield. That field is written only after thecontainer starts successfully, so a node crash (or error) between
createNetworkand thatpersist leaked the network with
networkId=''in the DB. From then on, restart skippedteardown (empty id), hit the leftover named network at
createNetwork→ Docker 409 → jobmarked
Error— a self-perpetuating dead end. Leaked networks were also never reaped by theexpiry sweep (same gate), permanently consuming the Docker daemon's limited IPAM subnet pool.
What changed
All in
src/components/c2d/compute_engine_docker.ts:removeServiceNetwork(serviceId, networkId?)(new): removes the service network byboth the persisted id (when set) and the deterministic name, so cleanup never depends
solely on the DB field. If the network still has stale attached containers (crash after
container.start()but before the persist), they are force-removed first — otherwisenetwork.remove()fails with "has active endpoints". Benign Docker errors (404/304 =already gone) count as success; anything else propagates.
createServiceNetwork(serviceId)(new): wrapscreateNetwork; on a 409 name conflictit removes the stale network and retries once. This makes already-broken jobs (like the
reported one) self-heal on the next restart with no manual intervention or DB surgery.
The stale network is removed and recreated rather than reused: reuse saves nothing (a
leaked network can still hold a stale container bound to the service's host ports, which
must be inspected and force-removed either way), a fresh network always reflects the
current code's configuration instead of inheriting options from whatever node version
leaked it, and remove+recreate matches restart's tear-down-and-rebuild semantics — the
container is never reused either.
restartServicepre-teardown,stopService,processServiceStartorphan recovery, andcleanupServiceDocker(failure-path cleanup — now works even when
createNetworkitself threw and no livehandle exists). Both
createNetworkcall sites (initial start + restart) use theself-healing wrapper.
Running/Errorjobs throughstopService, leakednetworks from abandoned jobs are now reaped automatically too — no schema or sweep changes.
isBenignDockerErrorhoisted fromstopServiceto module scope (shared, unchanged).No handler/API changes:
Error-status jobs were already restartable; the bug was entirelyengine-side.
markServiceFailedstill deliberately leaves Docker resources in place forrestart to reclaim — reclaiming is just reliable now.
Tests
src/test/unit/service/serviceNetworkCleanup.test.ts, no Docker daemon):removal by deterministic name with empty
networkId(the exact leak scenario), staleattached containers force-removed before network removal, benign 404/304 vs propagated
errors, 409 → remove + retry-once (and no retry on other errors), and
stopServiceend-to-end with a leaked network ending
Stopped.src/test/integration/services.test.ts): new case simulates thepost-crash DB state (
containerId='',networkId='',status=Errorwhile the realcontainer + network keep running) and asserts
SERVICE_RESTARTsucceeds (pre-fix: 500with the 409 message), the service returns to
Runningon the same host port, the stalecontainer is gone, and exactly one
ocean-svc-<serviceId>network remains. The stop testnow also asserts the network is gone by name.
docs/services.mdnotes the self-healing teardown semantics.Summary by CodeRabbit
Bug Fixes
Documentation
Tests