@@ -55,6 +55,19 @@ const (
5555type convergence struct {
5656 service * composeService
5757 observedState map [string ]Containers
58+ stateMutex sync.Mutex
59+ }
60+
61+ func (c * convergence ) getObservedState (serviceName string ) Containers {
62+ c .stateMutex .Lock ()
63+ defer c .stateMutex .Unlock ()
64+ return c .observedState [serviceName ]
65+ }
66+
67+ func (c * convergence ) setObservedState (serviceName string , containers Containers ) {
68+ c .stateMutex .Lock ()
69+ defer c .stateMutex .Unlock ()
70+ c .observedState [serviceName ] = containers
5871}
5972
6073func newConvergence (services []string , state Containers , s * composeService ) * convergence {
@@ -97,7 +110,7 @@ var mu sync.Mutex
97110
98111// updateProject updates project after service converged, so dependent services relying on `service:xx` can refer to actual containers.
99112func (c * convergence ) updateProject (project * types.Project , service string ) {
100- containers := c .observedState [ service ]
113+ containers := c .getObservedState ( service )
101114 container := containers [0 ]
102115
103116 // operation is protected by a Mutex so that we can safely update project.Services while running concurrent convergence on services
@@ -148,7 +161,7 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
148161 if err != nil {
149162 return err
150163 }
151- containers := c .observedState [ service .Name ]
164+ containers := c .getObservedState ( service .Name )
152165 actual := len (containers )
153166 updated := make (Containers , expected )
154167
@@ -157,6 +170,7 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
157170 for i , container := range containers {
158171 if i > expected {
159172 // Scale Down
173+ container := container
160174 eg .Go (func () error {
161175 err := c .service .apiClient .ContainerStop (ctx , container .ID , timeout )
162176 if err != nil {
@@ -178,7 +192,7 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
178192 name := getContainerProgressName (container )
179193 diverged := container .Labels [api .ConfigHashLabel ] != configHash
180194 if diverged || recreate == api .RecreateForce || service .Extensions [extLifecycle ] == forceRecreate {
181- i := i
195+ i , container := i , container
182196 eg .Go (func () error {
183197 recreated , err := c .service .recreateContainer (ctx , project , service , container , inherit , timeout )
184198 updated [i ] = recreated
@@ -197,6 +211,7 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
197211 case ContainerExited :
198212 w .Event (progress .CreatedEvent (name ))
199213 default :
214+ container := container
200215 eg .Go (func () error {
201216 return c .service .startContainer (ctx , container )
202217 })
@@ -212,16 +227,17 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
212227 // Scale UP
213228 number := next + i
214229 name := getContainerName (project .Name , service , number )
230+ i := i
215231 eg .Go (func () error {
216232 container , err := c .service .createContainer (ctx , project , service , name , number , false , true )
217- updated [actual + i - 1 ] = container
233+ updated [actual + i ] = container
218234 return err
219235 })
220236 continue
221237 }
222238
223239 err = eg .Wait ()
224- c .observedState [ service .Name ] = updated
240+ c .setObservedState ( service .Name , updated )
225241 return err
226242}
227243
@@ -542,11 +558,11 @@ func (s *composeService) startService(ctx context.Context, project *types.Projec
542558
543559 w := progress .ContextWriter (ctx )
544560 eg , ctx := errgroup .WithContext (ctx )
545- for _ , c := range containers {
546- container := c
561+ for _ , container := range containers {
547562 if container .State == ContainerRunning {
548563 continue
549564 }
565+ container := container
550566 eg .Go (func () error {
551567 eventName := getContainerProgressName (container )
552568 w .Event (progress .StartingEvent (eventName ))
0 commit comments