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

Code before:
)

func (s *composeService) Restart(ctx context.Context, projectName string, options api.RestartOptions) error {
	return progress.RunWithTitle(ctx, func(ctx context.Context) error {
		return s.restart(ctx, strings.ToLower(projectName), options)
	}, s.stdinfo(), "Restarting")
}

func (s *composeService) restart(ctx context.Context, projectName string, options api.RestartOptions) error {
	containers, err := s.getContainers(ctx, projectName, oneOffExclude, true)
	if err != nil {
		return err
	}

	project := options.Project
	if project == nil {
		project, err = s.getProjectWithResources(ctx, containers, projectName)
		if err != nil {
			return err
		}
	}

	// ignore depends_on relations which are not impacted by restarting service or not required
	for i, service := range project.Services {
		for name, r := range service.DependsOn {
			if !r.Restart || !r.Required {
				delete(service.DependsOn, name)
			}
		}
		project.Services[i] = service
	}

	if len(options.Services) != 0 {
		err = project.ForServices(options.Services, types.IncludeDependents)
		if err != nil {
			return err
		}
	}

	w := progress.ContextWriter(ctx)
	return InDependencyOrder(ctx, project, func(c context.Context, service string) error {
		eg, ctx := errgroup.WithContext(ctx)
		for _, container := range containers.filter(isService(service)) {
			container := container
			eg.Go(func() error {
				eventName := getContainerProgressName(container)
				w.Event(progress.RestartingEvent(eventName))
				timeout := utils.DurationSecondToInt(options.Timeout)
				err := s.apiClient().ContainerRestart(ctx, container.ID, containerType.StopOptions{Timeout: timeout})
				if err == nil {
					w.Event(progress.StartedEvent(eventName))

Review comment (bug):
Similar to @ndeloof's [Q around wait](https://github.com/docker/compose/pull/10792/files#r1266706274), should this not filter them out, but ignore any failures attempting to restart IF it was not required?

Code after:
)

func (s *composeService) Restart(ctx context.Context, projectName string, options api.RestartOptions) error {
	return progress.RunWithTitle(ctx, func(ctx context.Context) error {
		return s.restart(ctx, strings.ToLower(projectName), options)
	}, s.stdinfo(), "Restarting")
}

func (s *composeService) restart(ctx context.Context, projectName string, options api.RestartOptions) error {
	containers, err := s.getContainers(ctx, projectName, oneOffExclude, true)
	if err != nil {
		return err
	}

	project := options.Project
	if project == nil {
		project, err = s.getProjectWithResources(ctx, containers, projectName)
		if err != nil {
			return err
		}
	}

	// ignore depends_on relations which are not impacted by restarting service or not required
	for i, service := range project.Services {
		for name, r := range service.DependsOn {
			if !r.Restart {
				delete(service.DependsOn, name)
			}
		}
		project.Services[i] = service
	}

	if len(options.Services) != 0 {
		err = project.ForServices(options.Services, types.IncludeDependents)
		if err != nil {
			return err
		}
	}

	w := progress.ContextWriter(ctx)
	return InDependencyOrder(ctx, project, func(c context.Context, service string) error {
		eg, ctx := errgroup.WithContext(ctx)
		for _, container := range containers.filter(isService(service)) {
			container := container
			eg.Go(func() error {
				eventName := getContainerProgressName(container)
				w.Event(progress.RestartingEvent(eventName))
				timeout := utils.DurationSecondToInt(options.Timeout)
				err := s.apiClient().ContainerRestart(ctx, container.ID, containerType.StopOptions{Timeout: timeout})
				if err == nil {
					w.Event(progress.StartedEvent(eventName))