@@ -28,7 +28,6 @@ import (
28
28
"github.com/containerd/containerd/platforms"
29
29
moby "github.com/docker/docker/api/types"
30
30
containerType "github.com/docker/docker/api/types/container"
31
- "github.com/docker/docker/api/types/filters"
32
31
"github.com/docker/docker/api/types/network"
33
32
specs "github.com/opencontainers/image-spec/specs-go/v1"
34
33
"github.com/pkg/errors"
@@ -281,7 +280,7 @@ func containerEvents(containers Containers, eventFunc func(string) progress.Even
281
280
// ServiceConditionRunningOrHealthy is a service condition on status running or healthy
282
281
const ServiceConditionRunningOrHealthy = "running_or_healthy"
283
282
284
- func (s * composeService ) waitDependencies (ctx context.Context , project * types.Project , dependencies types.DependsOnConfig ) error {
283
+ func (s * composeService ) waitDependencies (ctx context.Context , project * types.Project , dependencies types.DependsOnConfig , containers Containers ) error {
285
284
eg , _ := errgroup .WithContext (ctx )
286
285
w := progress .ContextWriter (ctx )
287
286
for dep , config := range dependencies {
@@ -291,11 +290,8 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr
291
290
continue
292
291
}
293
292
294
- containers , err := s .getContainers (ctx , project .Name , oneOffExclude , false , dep )
295
- if err != nil {
296
- return err
297
- }
298
- w .Events (containerEvents (containers , progress .Waiting ))
293
+ waitingFor := containers .filter (isService (dep ))
294
+ w .Events (containerEvents (waitingFor , progress .Waiting ))
299
295
300
296
dep , config := dep , config
301
297
eg .Go (func () error {
@@ -305,31 +301,31 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr
305
301
<- ticker .C
306
302
switch config .Condition {
307
303
case ServiceConditionRunningOrHealthy :
308
- healthy , err := s .isServiceHealthy (ctx , project , dep , true )
304
+ healthy , err := s .isServiceHealthy (ctx , waitingFor , true )
309
305
if err != nil {
310
306
return err
311
307
}
312
308
if healthy {
313
- w .Events (containerEvents (containers , progress .Healthy ))
309
+ w .Events (containerEvents (waitingFor , progress .Healthy ))
314
310
return nil
315
311
}
316
312
case types .ServiceConditionHealthy :
317
- healthy , err := s .isServiceHealthy (ctx , project , dep , false )
313
+ healthy , err := s .isServiceHealthy (ctx , waitingFor , false )
318
314
if err != nil {
319
- w .Events (containerEvents (containers , progress .ErrorEvent ))
315
+ w .Events (containerEvents (waitingFor , progress .ErrorEvent ))
320
316
return errors .Wrap (err , "dependency failed to start" )
321
317
}
322
318
if healthy {
323
- w .Events (containerEvents (containers , progress .Healthy ))
319
+ w .Events (containerEvents (waitingFor , progress .Healthy ))
324
320
return nil
325
321
}
326
322
case types .ServiceConditionCompletedSuccessfully :
327
- exited , code , err := s .isServiceCompleted (ctx , project , dep )
323
+ exited , code , err := s .isServiceCompleted (ctx , waitingFor )
328
324
if err != nil {
329
325
return err
330
326
}
331
327
if exited {
332
- w .Events (containerEvents (containers , progress .Exited ))
328
+ w .Events (containerEvents (waitingFor , progress .Exited ))
333
329
if code != 0 {
334
330
return fmt .Errorf ("service %q didn't complete successfully: exit %d" , dep , code )
335
331
}
@@ -650,51 +646,41 @@ func (s *composeService) connectContainerToNetwork(ctx context.Context, id strin
650
646
return nil
651
647
}
652
648
653
- func (s * composeService ) isServiceHealthy (ctx context.Context , project * types.Project , service string , fallbackRunning bool ) (bool , error ) {
654
- containers , err := s .getContainers (ctx , project .Name , oneOffExclude , true , service )
655
- if err != nil {
656
- return false , err
657
- }
658
-
659
- if len (containers ) == 0 {
660
- return false , nil
661
- }
649
+ func (s * composeService ) isServiceHealthy (ctx context.Context , containers Containers , fallbackRunning bool ) (bool , error ) {
662
650
for _ , c := range containers {
663
651
container , err := s .apiClient ().ContainerInspect (ctx , c .ID )
664
652
if err != nil {
665
653
return false , err
666
654
}
655
+ name := container .Name [1 :]
656
+
657
+ if container .State .Status == "exited" {
658
+ return false , fmt .Errorf ("container %s exited (%d)" , name , container .State .ExitCode )
659
+ }
660
+
667
661
if container .Config .Healthcheck == nil && fallbackRunning {
668
662
// Container does not define a health check, but we can fall back to "running" state
669
663
return container .State != nil && container .State .Status == "running" , nil
670
664
}
671
665
672
- if container .State .Status == "exited" {
673
- return false , fmt .Errorf ("container for service %q exited (%d)" , service , container .State .ExitCode )
674
- }
675
-
676
666
if container .State == nil || container .State .Health == nil {
677
- return false , fmt .Errorf ("container for service %q has no healthcheck configured" , service )
667
+ return false , fmt .Errorf ("container %s has no healthcheck configured" , name )
678
668
}
679
669
switch container .State .Health .Status {
680
670
case moby .Healthy :
681
671
// Continue by checking the next container.
682
672
case moby .Unhealthy :
683
- return false , fmt .Errorf ("container for service %q is unhealthy" , service )
673
+ return false , fmt .Errorf ("container %s is unhealthy" , name )
684
674
case moby .Starting :
685
675
return false , nil
686
676
default :
687
- return false , fmt .Errorf ("container for service %q had unexpected health status %q" , service , container .State .Health .Status )
677
+ return false , fmt .Errorf ("container %s had unexpected health status %q" , name , container .State .Health .Status )
688
678
}
689
679
}
690
680
return true , nil
691
681
}
692
682
693
- func (s * composeService ) isServiceCompleted (ctx context.Context , project * types.Project , dep string ) (bool , int , error ) {
694
- containers , err := s .getContainers (ctx , project .Name , oneOffExclude , true , dep )
695
- if err != nil {
696
- return false , 0 , err
697
- }
683
+ func (s * composeService ) isServiceCompleted (ctx context.Context , containers Containers ) (bool , int , error ) {
698
684
for _ , c := range containers {
699
685
container , err := s .apiClient ().ContainerInspect (ctx , c .ID )
700
686
if err != nil {
@@ -707,23 +693,12 @@ func (s *composeService) isServiceCompleted(ctx context.Context, project *types.
707
693
return false , 0 , nil
708
694
}
709
695
710
- func (s * composeService ) startService (ctx context.Context , project * types.Project , service types.ServiceConfig ) error {
696
+ func (s * composeService ) startService (ctx context.Context , project * types.Project , service types.ServiceConfig , containers Containers ) error {
711
697
if service .Deploy != nil && service .Deploy .Replicas != nil && * service .Deploy .Replicas == 0 {
712
698
return nil
713
699
}
714
700
715
- err := s .waitDependencies (ctx , project , service .DependsOn )
716
- if err != nil {
717
- return err
718
- }
719
- containers , err := s .apiClient ().ContainerList (ctx , moby.ContainerListOptions {
720
- Filters : filters .NewArgs (
721
- projectFilter (project .Name ),
722
- serviceFilter (service .Name ),
723
- oneOffFilter (false ),
724
- ),
725
- All : true ,
726
- })
701
+ err := s .waitDependencies (ctx , project , service .DependsOn , containers )
727
702
if err != nil {
728
703
return err
729
704
}
@@ -736,7 +711,7 @@ func (s *composeService) startService(ctx context.Context, project *types.Projec
736
711
}
737
712
738
713
w := progress .ContextWriter (ctx )
739
- for _ , container := range containers {
714
+ for _ , container := range containers . filter ( isService ( service . Name )) {
740
715
if container .State == ContainerRunning {
741
716
continue
742
717
}
0 commit comments