Skip to content

Commit 46e274e

Browse files
ndeloofclaude
andcommitted
Cleanup: remove convergence struct, extract resolveServiceReferences
- Remove the `convergence` struct and `newConvergence` constructor - Extract `resolveServiceReferences` as a standalone function taking `map[string]Containers` instead of a method on convergence - Add `getContainersByService` helper on composeService - Update run.go and executor.go to use the new standalone function - Remove dead code: `getObservedState`, `setObservedState` Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> Signed-off-by: Nicolas De Loof <[email protected]>
1 parent a062d54 commit 46e274e

4 files changed

Lines changed: 41 additions & 58 deletions

File tree

pkg/compose/containers.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@ func (s *composeService) getContainers(ctx context.Context, project string, oneO
5656
return containers, nil
5757
}
5858

59+
// getContainersByService returns all non-oneoff containers for the project, grouped by service name.
60+
func (s *composeService) getContainersByService(ctx context.Context, projectName string) (map[string]Containers, error) {
61+
all, err := s.getContainers(ctx, projectName, oneOffExclude, true)
62+
if err != nil {
63+
return nil, err
64+
}
65+
result := map[string]Containers{}
66+
for _, c := range all.filter(isNotOneOff) {
67+
svc := c.Labels[api.ServiceLabel]
68+
result[svc] = append(result[svc], c)
69+
}
70+
return result, nil
71+
}
72+
5973
func getDefaultFilters(projectName string, oneOff oneOff, selectedServices ...string) client.Filters {
6074
f := projectFilter(projectName)
6175
if len(selectedServices) == 1 {

pkg/compose/convergence.go

Lines changed: 16 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -49,37 +49,6 @@ const (
4949
// re-creating container, adding or removing replicas, or starting stopped containers.
5050
// Cross services dependencies are managed by creating services in expected order and updating `service:xx` reference
5151
// when a service has converged, so dependent ones can be managed with resolved containers references.
52-
type convergence struct {
53-
compose *composeService
54-
services map[string]Containers
55-
networks map[string]string
56-
volumes map[string]string
57-
stateMutex sync.Mutex
58-
}
59-
60-
func (c *convergence) getObservedState(serviceName string) Containers {
61-
c.stateMutex.Lock()
62-
defer c.stateMutex.Unlock()
63-
return c.services[serviceName]
64-
}
65-
66-
func newConvergence(services []string, state Containers, networks map[string]string, volumes map[string]string, s *composeService) *convergence {
67-
observedState := map[string]Containers{}
68-
for _, s := range services {
69-
observedState[s] = Containers{}
70-
}
71-
for _, c := range state.filter(isNotOneOff) {
72-
service := c.Labels[api.ServiceLabel]
73-
observedState[service] = append(observedState[service], c)
74-
}
75-
return &convergence{
76-
compose: s,
77-
services: observedState,
78-
networks: networks,
79-
volumes: volumes,
80-
}
81-
}
82-
8352
func getScale(config types.ServiceConfig) (int, error) {
8453
scale := config.GetScale()
8554
if scale > 1 && config.ContainerName != "" {
@@ -90,21 +59,18 @@ func getScale(config types.ServiceConfig) (int, error) {
9059
return scale, nil
9160
}
9261

93-
// resolveServiceReferences replaces reference to another service with reference to an actual container
94-
func (c *convergence) resolveServiceReferences(service *types.ServiceConfig) error {
95-
err := c.resolveVolumeFrom(service)
96-
if err != nil {
62+
// resolveServiceReferences replaces references to other services with references
63+
// to actual container IDs. It resolves VolumesFrom, NetworkMode, IPC and PID
64+
// shared namespaces. The containersByService map provides the observed containers
65+
// grouped by service name.
66+
func resolveServiceReferences(service *types.ServiceConfig, containersByService map[string]Containers) error {
67+
if err := resolveVolumeFrom(service, containersByService); err != nil {
9768
return err
9869
}
99-
100-
err = c.resolveSharedNamespaces(service)
101-
if err != nil {
102-
return err
103-
}
104-
return nil
70+
return resolveSharedNamespaces(service, containersByService)
10571
}
10672

107-
func (c *convergence) resolveVolumeFrom(service *types.ServiceConfig) error {
73+
func resolveVolumeFrom(service *types.ServiceConfig, containersByService map[string]Containers) error {
10874
for i, vol := range service.VolumesFrom {
10975
spec := strings.Split(vol, ":")
11076
if len(spec) == 0 {
@@ -115,7 +81,7 @@ func (c *convergence) resolveVolumeFrom(service *types.ServiceConfig) error {
11581
continue
11682
}
11783
name := spec[0]
118-
dependencies := c.getObservedState(name)
84+
dependencies := containersByService[name]
11985
if len(dependencies) == 0 {
12086
return fmt.Errorf("cannot share volume with service %s: container missing", name)
12187
}
@@ -124,28 +90,25 @@ func (c *convergence) resolveVolumeFrom(service *types.ServiceConfig) error {
12490
return nil
12591
}
12692

127-
func (c *convergence) resolveSharedNamespaces(service *types.ServiceConfig) error {
128-
str := service.NetworkMode
129-
if name := getDependentServiceFromMode(str); name != "" {
130-
dependencies := c.getObservedState(name)
93+
func resolveSharedNamespaces(service *types.ServiceConfig, containersByService map[string]Containers) error {
94+
if name := getDependentServiceFromMode(service.NetworkMode); name != "" {
95+
dependencies := containersByService[name]
13196
if len(dependencies) == 0 {
13297
return fmt.Errorf("cannot share network namespace with service %s: container missing", name)
13398
}
13499
service.NetworkMode = types.ContainerPrefix + dependencies.sorted()[0].ID
135100
}
136101

137-
str = service.Ipc
138-
if name := getDependentServiceFromMode(str); name != "" {
139-
dependencies := c.getObservedState(name)
102+
if name := getDependentServiceFromMode(service.Ipc); name != "" {
103+
dependencies := containersByService[name]
140104
if len(dependencies) == 0 {
141105
return fmt.Errorf("cannot share IPC namespace with service %s: container missing", name)
142106
}
143107
service.Ipc = types.ContainerPrefix + dependencies.sorted()[0].ID
144108
}
145109

146-
str = service.Pid
147-
if name := getDependentServiceFromMode(str); name != "" {
148-
dependencies := c.getObservedState(name)
110+
if name := getDependentServiceFromMode(service.Pid); name != "" {
111+
dependencies := containersByService[name]
149112
if len(dependencies) == 0 {
150113
return fmt.Errorf("cannot share PID namespace with service %s: container missing", name)
151114
}

pkg/compose/executor.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,11 @@ func (exec *planExecutor) execCreateContainer(ctx context.Context, node *PlanNod
198198
// Resolve service references (network_mode, ipc, pid, volumes_from) to actual
199199
// container IDs. This must happen at execution time because the referenced
200200
// containers may have just been created by earlier plan nodes.
201-
observedState, err := exec.compose.getContainers(ctx, exec.project.Name, oneOffExclude, true)
201+
containersByService, err := exec.compose.getContainersByService(ctx, exec.project.Name)
202202
if err != nil {
203203
return err
204204
}
205-
conv := newConvergence(exec.project.ServiceNames(), observedState, nil, nil, exec.compose)
206-
if err := conv.resolveServiceReferences(&service); err != nil {
205+
if err := resolveServiceReferences(&service, containersByService); err != nil {
207206
return err
208207
}
209208

pkg/compose/run.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,7 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
181181
Labels: mergeLabels(service.Labels, service.CustomLabels),
182182
}
183183

184-
err = newConvergence(project.ServiceNames(), observedState, nil, nil, s).resolveServiceReferences(&service)
185-
if err != nil {
184+
if err := s.resolveRunServiceReferences(ctx, project.Name, &service); err != nil {
186185
return prepareRunResult{}, err
187186
}
188187

@@ -269,6 +268,14 @@ func applyRunOptions(project *types.Project, service *types.ServiceConfig, opts
269268
}
270269
}
271270

271+
func (s *composeService) resolveRunServiceReferences(ctx context.Context, projectName string, service *types.ServiceConfig) error {
272+
containersByService, err := s.getContainersByService(ctx, projectName)
273+
if err != nil {
274+
return err
275+
}
276+
return resolveServiceReferences(service, containersByService)
277+
}
278+
272279
func (s *composeService) startDependencies(ctx context.Context, project *types.Project, options api.RunOptions) error {
273280
project = project.WithServicesDisabled(options.Service)
274281

0 commit comments

Comments
 (0)