diff --git a/api/compose/api.go b/api/compose/api.go index dfd919333..5efc209ee 100644 --- a/api/compose/api.go +++ b/api/compose/api.go @@ -77,6 +77,8 @@ type CreateOptions struct { RecreateDependencies string // Inherit reuse anonymous volumes from previous container Inherit bool + // Timeout set delay to wait for container to gracelfuly stop before sending SIGKILL + Timeout *time.Duration } // StartOptions group options of the Start API diff --git a/cli/cmd/compose/up.go b/cli/cmd/compose/up.go index 8d397d46f..a97e0d09c 100644 --- a/cli/cmd/compose/up.go +++ b/cli/cmd/compose/up.go @@ -19,12 +19,6 @@ package compose import ( "context" "fmt" - "github.com/docker/compose-cli/api/client" - "github.com/docker/compose-cli/api/compose" - "github.com/docker/compose-cli/api/context/store" - "github.com/docker/compose-cli/api/progress" - "github.com/docker/compose-cli/cli/cmd" - "github.com/docker/compose-cli/cli/formatter" "os" "os/signal" "path/filepath" @@ -37,6 +31,13 @@ import ( "github.com/sirupsen/logrus" "github.com/spf13/cobra" "golang.org/x/sync/errgroup" + + "github.com/docker/compose-cli/api/client" + "github.com/docker/compose-cli/api/compose" + "github.com/docker/compose-cli/api/context/store" + "github.com/docker/compose-cli/api/progress" + "github.com/docker/compose-cli/cli/cmd" + "github.com/docker/compose-cli/cli/formatter" ) // composeOptions hold options common to `up` and `run` to run compose project @@ -68,26 +69,34 @@ type upOptions struct { noInherit bool } -func (o upOptions) recreateStrategy() string { - if o.noRecreate { +func (opts upOptions) recreateStrategy() string { + if opts.noRecreate { return compose.RecreateNever } - if o.forceRecreate { + if opts.forceRecreate { return compose.RecreateForce } return compose.RecreateDiverged } -func (o upOptions) dependenciesRecreateStrategy() string { - if o.noRecreate { +func (opts upOptions) dependenciesRecreateStrategy() string { + if opts.noRecreate { return compose.RecreateNever } - if o.recreateDeps { + if opts.recreateDeps { return compose.RecreateForce } return compose.RecreateDiverged } +func (opts upOptions) GetTimeout() *time.Duration { + if opts.timeChanged { + t := time.Duration(opts.timeout) * time.Second + return &t + } + return nil +} + func (opts upOptions) apply(project *types.Project, services []string) error { if opts.noDeps { enabled, err := project.GetServices(services...) @@ -109,14 +118,6 @@ func (opts upOptions) apply(project *types.Project, services []string) error { } } - if opts.timeChanged { - timeoutValue := types.Duration(time.Duration(opts.timeout) * time.Second) - for i, s := range project.Services { - s.StopGracePeriod = &timeoutValue - project.Services[i] = s - } - } - for _, scale := range opts.scale { split := strings.Split(scale, "=") if len(split) != 2 { @@ -235,6 +236,7 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro Recreate: opts.recreateStrategy(), RecreateDependencies: opts.dependenciesRecreateStrategy(), Inherit: !opts.noInherit, + Timeout: opts.GetTimeout(), }) if err != nil { return "", err diff --git a/local/compose/convergence.go b/local/compose/convergence.go index aaf8bc0a2..fe0571a56 100644 --- a/local/compose/convergence.go +++ b/local/compose/convergence.go @@ -42,7 +42,7 @@ const ( "Remove the custom name to scale the service.\n" ) -func (s *composeService) ensureScale(ctx context.Context, project *types.Project, service types.ServiceConfig) (*errgroup.Group, []moby.Container, error) { +func (s *composeService) ensureScale(ctx context.Context, project *types.Project, service types.ServiceConfig, timeout *time.Duration) (*errgroup.Group, []moby.Container, error) { cState, err := GetContextContainerState(ctx) if err != nil { return nil, nil, err @@ -73,7 +73,7 @@ func (s *composeService) ensureScale(ctx context.Context, project *types.Project for i := scale; i < len(actual); i++ { container := actual[i] eg.Go(func() error { - err := s.apiClient.ContainerStop(ctx, container.ID, nil) + err := s.apiClient.ContainerStop(ctx, container.ID, timeout) if err != nil { return err } @@ -85,8 +85,8 @@ func (s *composeService) ensureScale(ctx context.Context, project *types.Project return eg, actual, nil } -func (s *composeService) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig, recreate string, inherit bool) error { - eg, actual, err := s.ensureScale(ctx, project, service) +func (s *composeService) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig, recreate string, inherit bool, timeout *time.Duration) error { + eg, actual, err := s.ensureScale(ctx, project, service, timeout) if err != nil { return err } @@ -106,7 +106,7 @@ func (s *composeService) ensureService(ctx context.Context, project *types.Proje diverged := container.Labels[configHashLabel] != expected if diverged || recreate == compose.RecreateForce || service.Extensions[extLifecycle] == forceRecreate { eg.Go(func() error { - return s.recreateContainer(ctx, project, service, container, inherit) + return s.recreateContainer(ctx, project, service, container, inherit, timeout) }) continue } @@ -209,10 +209,10 @@ func (s *composeService) createContainer(ctx context.Context, project *types.Pro return nil } -func (s *composeService) recreateContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, container moby.Container, inherit bool) error { +func (s *composeService) recreateContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, container moby.Container, inherit bool, timeout *time.Duration) error { w := progress.ContextWriter(ctx) w.Event(progress.NewEvent(getContainerProgressName(container), progress.Working, "Recreate")) - err := s.apiClient.ContainerStop(ctx, container.ID, nil) + err := s.apiClient.ContainerStop(ctx, container.ID, timeout) if err != nil { return err } diff --git a/local/compose/create.go b/local/compose/create.go index 123502030..f35557d9f 100644 --- a/local/compose/create.go +++ b/local/compose/create.go @@ -102,9 +102,9 @@ func (s *composeService) Create(ctx context.Context, project *types.Project, opt return InDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error { if contains(opts.Services, service.Name) { - return s.ensureService(c, project, service, opts.Recreate, opts.Inherit) + return s.ensureService(c, project, service, opts.Recreate, opts.Inherit, opts.Timeout) } - return s.ensureService(c, project, service, opts.RecreateDependencies, opts.Inherit) + return s.ensureService(c, project, service, opts.RecreateDependencies, opts.Inherit, opts.Timeout) }) }