Repository: docker/compose
File: pkg/compose/convergence.go (Go)

Code before:
func getContainerName(projectName string, service types.ServiceConfig, number int) string {
	name := strings.Join([]string{projectName, service.Name, strconv.Itoa(number)}, Separator)
	if service.ContainerName != "" {
		name = service.ContainerName
	}
	return name
}

func getContainerProgressName(container moby.Container) string {
	return "Container " + getCanonicalContainerName(container)
}

func (s *composeService) waitDependencies(ctx context.Context, project *types.Project, service types.ServiceConfig) error {
	eg, _ := errgroup.WithContext(ctx)
	for dep, config := range service.DependsOn {
		dep, config := dep, config
		eg.Go(func() error {
			ticker := time.NewTicker(500 * time.Millisecond)
			defer ticker.Stop()
			for {
				<-ticker.C
				switch config.Condition {
				case types.ServiceConditionHealthy:
					healthy, err := s.isServiceHealthy(ctx, project, dep)
					if err != nil {
						return err
					}
					if healthy {
						return nil
					}
				case types.ServiceConditionCompletedSuccessfully:
					exited, code, err := s.isServiceCompleted(ctx, project, dep)
					if err != nil {
						return err
					}
					if exited {
						if code != 0 {
							return fmt.Errorf("service %q didn't completed successfully: exit %d", dep, code)
						}
						return nil
					}
				case types.ServiceConditionStarted:
					// already managed by InDependencyOrder
					return nil
				default:
					logrus.Warnf("unsupported depends_on condition: %s", config.Condition)
					return nil
				}
			}
		})
	}

Review comment (suggestion):
(just thinking out loud); perhaps we need to have a look at the events API, and see if we can improve it enough so that compose can (more easily) use that. We already have a `health_status` event, but perhaps that alone is not sufficient, but we could look at enhancing it. (that way compose wouldn't have to poll `docker inspect` calls)

Code after:
func getContainerName(projectName string, service types.ServiceConfig, number int) string {
	name := strings.Join([]string{projectName, service.Name, strconv.Itoa(number)}, Separator)
	if service.ContainerName != "" {
		name = service.ContainerName
	}
	return name
}

func getContainerProgressName(container moby.Container) string {
	return "Container " + getCanonicalContainerName(container)
}

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 dependencies {
		dep, config := dep, config
		eg.Go(func() error {
			ticker := time.NewTicker(500 * time.Millisecond)
			defer ticker.Stop()
			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, false)
					if err != nil {
						return err
					}
					if healthy {
						return nil
					}
				case types.ServiceConditionCompletedSuccessfully:
					exited, code, err := s.isServiceCompleted(ctx, project, dep)
					if err != nil {
						return err
					}
					if exited {
						if code != 0 {
							return fmt.Errorf("service %q didn't completed successfully: exit %d", dep, code)
						}
						return nil
					}