From 1bc908e43ce73ff7b5711e0fc80389f10f120d54 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 17 Aug 2026 14:10:51 +0200 Subject: [PATCH] chore(compose): rename convergence.go, whose convergence engine no longer exists The convergence type this file was named after was removed in fbea647b9, but the file kept its name and its doc comment ('convergence manages service's container lifecycle') ended up attached to the unrelated getScale(). Anyone asked to 'change the convergence logic' lands here, while the actual reconciliation lives in reconcile.go. The file is renamed to service_containers.go with a header stating what it really contains: the per-service container helpers shared by both lifecycle engines (naming, service-reference resolution, dependency waiting, container creation, startup). getScale gets a doc comment that describes getScale. Part of #14074 (A: the code misdescribes its own structure). Signed-off-by: Nicolas De Loof --- pkg/compose/create.go | 2 +- pkg/compose/reconcile.go | 4 ++-- pkg/compose/reconcile_test.go | 2 +- .../{convergence.go => service_containers.go} | 16 +++++++++++----- ...rgence_test.go => service_containers_test.go} | 0 5 files changed, 15 insertions(+), 9 deletions(-) rename pkg/compose/{convergence.go => service_containers.go} (96%) rename pkg/compose/{convergence_test.go => service_containers_test.go} (100%) diff --git a/pkg/compose/create.go b/pkg/compose/create.go index c52c2e5863..ecc48d1333 100644 --- a/pkg/compose/create.go +++ b/pkg/compose/create.go @@ -659,7 +659,7 @@ func defaultNetworkSettings(project *types.Project, // in the network configuration instead of connecting the container to each extra // network individually after creation. // For older API versions, extra networks are connected via NetworkConnect after - // container creation (see createMobyContainer in convergence.go). + // container creation (see createMobyContainer in service_containers.go). if !versions.LessThan(version, apiVersion144) { for _, networkKey := range serviceNetworks { epSettings, err := createEndpointSettings(project, service, serviceIndex, networkKey, links, useNetworkAliases) diff --git a/pkg/compose/reconcile.go b/pkg/compose/reconcile.go index 752e303ba3..0f3e78e3da 100644 --- a/pkg/compose/reconcile.go +++ b/pkg/compose/reconcile.go @@ -716,7 +716,7 @@ func (r *reconciler) reconcileService(service types.ServiceConfig) error { // Container is up-to-date switch oc.State { case container.StateRunning, container.StateCreated, container.StateRestarting, container.StateExited: - // Nothing to do (exited containers are left as-is, matching convergence.go behavior) + // Nothing to do (exited containers are left as-is, matching service_containers.go behavior) default: // Any other state (paused, dead, ...): attempt to (re)start lastNode = r.plan.addNode(Operation{ @@ -1009,7 +1009,7 @@ func (r *reconciler) infrastructureDeps(service types.ServiceConfig) []*PlanNode return deps } -// sortContainers sorts containers the same way as convergence.go:138-160: +// sortContainers sorts containers the same way as the start path in service_containers.go: // obsolete first, then by container number descending, then reversed. // // mustRecreate is evaluated once per container before sorting to avoid diff --git a/pkg/compose/reconcile_test.go b/pkg/compose/reconcile_test.go index 8f58122669..94b08aba85 100644 --- a/pkg/compose/reconcile_test.go +++ b/pkg/compose/reconcile_test.go @@ -1242,7 +1242,7 @@ func TestReconcileContainers_ExitedIsNoop(t *testing.T) { plan, err := reconcile(t.Context(), project, observed, defaultReconcileOptions(), noPrompt) assert.NilError(t, err) - // Exited containers are left as-is, matching convergence.go:199 behavior + // Exited containers are left as-is: starting containers is not the plan engine's job assert.Assert(t, plan.IsEmpty()) } diff --git a/pkg/compose/convergence.go b/pkg/compose/service_containers.go similarity index 96% rename from pkg/compose/convergence.go rename to pkg/compose/service_containers.go index bbead3746a..bf6486bbfe 100644 --- a/pkg/compose/convergence.go +++ b/pkg/compose/service_containers.go @@ -38,17 +38,23 @@ import ( "github.com/docker/compose/v5/pkg/api" ) +// This file gathers the per-service container helpers shared by both +// lifecycle engines: the plan-based reconciler (reconcile.go, entered through +// create/up) and the imperative dependency-ordered engine (dependencies.go, +// used by start/stop/restart/down). It covers container naming, resolution of +// service references (volumes_from, network_mode/ipc/pid, links), dependency +// waiting, container creation through the Docker API, and service startup. + const ( doubledContainerNameWarning = "WARNING: The %q service is using the custom container name %q. " + "Docker requires each container to have a unique name. " + "Remove the custom name to scale the service" ) -// convergence manages service's container lifecycle. -// Based on initially observed state, it reconciles the existing container with desired state, which might include -// re-creating container, adding or removing replicas, or starting stopped containers. -// Cross services dependencies are managed by creating services in expected order and updating `service:xx` reference -// when a service has converged, so dependent ones can be managed with resolved containers references. +// getScale returns the number of replicas the service must run. A service +// pinned to a custom container_name cannot scale beyond one replica, as every +// container needs a distinct name: this is rejected here rather than at +// container-creation time. func getScale(config types.ServiceConfig) (int, error) { scale := config.GetScale() if scale > 1 && config.ContainerName != "" { diff --git a/pkg/compose/convergence_test.go b/pkg/compose/service_containers_test.go similarity index 100% rename from pkg/compose/convergence_test.go rename to pkg/compose/service_containers_test.go