up: gracefully teardown when command ctx cancelled

Previously, if a long-lived plugin process (such as
an execution of `compose up`) was running and then
detached from a terminal, signalling the parent CLI
process to exit would leave the plugin process behind.

To address this, changes were introduced on the CLI side
(see: https://github.com/docker/cli/pull/4599) to enable
the CLI to notify a running plugin process that it should
exit. This makes it so that, when the parent CLI process
is going to exit, the command context of the plugin
command being executed is cancelled.

This commit takes advantage of these changes by tapping into
the command context's done channel and using it to teardown
on an up.

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
This commit is contained in:
Laura Brehm 2023-12-20 17:45:51 +00:00
parent ce5a0c656f
commit dcbf005fe4
No known key found for this signature in database
GPG Key ID: CFBF847B4A313468
2 changed files with 21 additions and 19 deletions

View File

@ -278,12 +278,7 @@ const PluginName = "compose"
// RunningAsStandalone detects when running as a standalone program
func RunningAsStandalone() bool {
println("check running as standalone")
standalone := len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName && os.Args[1] != PluginName
fmt.Fprintf(os.Stderr, "%v+\n", os.Args)
println("len os.args", len(os.Args))
println("STANDALONE:", standalone)
return standalone
return len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName && os.Args[1] != PluginName
}
// RootCommand returns the compose command with its child commands

View File

@ -31,7 +31,7 @@ import (
"github.com/hashicorp/go-multierror"
)
func (s *composeService) Up(ctx context.Context, project *types.Project, options api.UpOptions) error {
func (s *composeService) Up(ctx context.Context, project *types.Project, options api.UpOptions) error { //nolint:gocyclo
err := progress.Run(ctx, tracing.SpanWrapFunc("project/up", tracing.ProjectOptions(project), func(ctx context.Context) error {
err := s.create(ctx, project, options.Create)
if err != nil {
@ -69,24 +69,31 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
doneCh := make(chan bool)
eg.Go(func() error {
first := true
gracefulTeardown := func() {
printer.Cancel()
fmt.Fprintln(s.stdinfo(), "Gracefully stopping... (press Ctrl+C again to force)")
eg.Go(func() error {
err := s.Stop(context.Background(), project.Name, api.StopOptions{
Services: options.Create.Services,
Project: project,
})
isTerminated = true
close(doneCh)
return err
})
first = false
}
for {
select {
case <-doneCh:
return nil
case <-ctx.Done():
if first {
gracefulTeardown()
}
case <-signalChan:
if first {
printer.Cancel()
fmt.Fprintln(s.stdinfo(), "Gracefully stopping... (press Ctrl+C again to force)")
eg.Go(func() error {
err := s.Stop(context.Background(), project.Name, api.StopOptions{
Services: options.Create.Services,
Project: project,
})
isTerminated = true
close(doneCh)
return err
})
first = false
gracefulTeardown()
} else {
eg.Go(func() error {
return s.Kill(context.Background(), project.Name, api.KillOptions{