mirror of
https://github.com/docker/compose.git
synced 2026-08-27 03:45:29 +00:00
introduce up --wait condition
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
9e6f51d262
commit
72e4519cbf
6 changed files with 72 additions and 22 deletions
|
|
@ -124,6 +124,8 @@ type StartOptions struct {
|
|||
CascadeStop bool
|
||||
// ExitCodeFrom return exit code from specified service
|
||||
ExitCodeFrom string
|
||||
// Wait won't return until containers reached the running|healthy state
|
||||
Wait bool
|
||||
}
|
||||
|
||||
// RestartOptions group options of the Restart API
|
||||
|
|
|
|||
|
|
@ -261,9 +261,11 @@ func getContainerProgressName(container moby.Container) string {
|
|||
return "Container " + getCanonicalContainerName(container)
|
||||
}
|
||||
|
||||
func (s *composeService) waitDependencies(ctx context.Context, project *types.Project, service types.ServiceConfig) error {
|
||||
const ServiceConditionRuningOrHealthy = "running_or_healthy"
|
||||
|
||||
func (s *composeService) waitDependencies(ctx context.Context, project *types.Project, dependencies types.DependsOnConfig) error {
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
for dep, config := range service.DependsOn {
|
||||
for dep, config := range dependencies {
|
||||
dep, config := dep, config
|
||||
eg.Go(func() error {
|
||||
ticker := time.NewTicker(500 * time.Millisecond)
|
||||
|
|
@ -271,8 +273,16 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr
|
|||
for {
|
||||
<-ticker.C
|
||||
switch config.Condition {
|
||||
case ServiceConditionRuningOrHealthy:
|
||||
healthy, err := s.isServiceHealthy(ctx, project, dep, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if healthy {
|
||||
return nil
|
||||
}
|
||||
case types.ServiceConditionHealthy:
|
||||
healthy, err := s.isServiceHealthy(ctx, project, dep)
|
||||
healthy, err := s.isServiceHealthy(ctx, project, dep, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -502,7 +512,7 @@ func (s *composeService) connectContainerToNetwork(ctx context.Context, id strin
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) isServiceHealthy(ctx context.Context, project *types.Project, service string) (bool, error) {
|
||||
func (s *composeService) isServiceHealthy(ctx context.Context, project *types.Project, service string, fallbackRunning bool) (bool, error) {
|
||||
containers, err := s.getContainers(ctx, project.Name, oneOffExclude, false, service)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
|
@ -516,6 +526,11 @@ func (s *composeService) isServiceHealthy(ctx context.Context, project *types.Pr
|
|||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if container.Config.Healthcheck == nil && fallbackRunning {
|
||||
// Container does not define a health check, but we can fall back to "running" state
|
||||
return container.State != nil && container.State.Status == "running", nil
|
||||
}
|
||||
|
||||
if container.State == nil || container.State.Health == nil {
|
||||
return false, fmt.Errorf("container for service %q has no healthcheck configured", service)
|
||||
}
|
||||
|
|
@ -544,7 +559,7 @@ func (s *composeService) isServiceCompleted(ctx context.Context, project *types.
|
|||
}
|
||||
|
||||
func (s *composeService) startService(ctx context.Context, project *types.Project, service types.ServiceConfig) error {
|
||||
err := s.waitDependencies(ctx, project, service)
|
||||
err := s.waitDependencies(ctx, project, service.DependsOn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -493,6 +493,7 @@ func getDeployResources(s types.ServiceConfig) container.Resources {
|
|||
MemorySwap: int64(s.MemSwapLimit),
|
||||
MemorySwappiness: swappiness,
|
||||
MemoryReservation: int64(s.MemReservation),
|
||||
OomKillDisable: &s.OomKillDisable,
|
||||
CPUCount: s.CPUCount,
|
||||
CPUPeriod: s.CPUPeriod,
|
||||
CPUQuota: s.CPUQuota,
|
||||
|
|
@ -503,6 +504,10 @@ func getDeployResources(s types.ServiceConfig) container.Resources {
|
|||
CpusetCpus: s.CPUSet,
|
||||
}
|
||||
|
||||
if s.PidsLimit != 0 {
|
||||
resources.PidsLimit = &s.PidsLimit
|
||||
}
|
||||
|
||||
setBlkio(s.BlkioConfig, &resources)
|
||||
|
||||
if s.Deploy != nil {
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
|
|||
return "", err
|
||||
}
|
||||
if !opts.NoDeps {
|
||||
if err := s.waitDependencies(ctx, project, service); err != nil {
|
||||
if err := s.waitDependencies(ctx, project, service.DependsOn); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,11 +58,26 @@ func (s *composeService) start(ctx context.Context, project *types.Project, opti
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.startService(ctx, project, service)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.Wait {
|
||||
depends := types.DependsOnConfig{}
|
||||
for _, s := range project.Services {
|
||||
depends[s.Name] = types.ServiceDependency{
|
||||
Condition: ServiceConditionRuningOrHealthy,
|
||||
}
|
||||
}
|
||||
err = s.waitDependencies(ctx, project, depends)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue