From c47dc5ecdbbd5f85703b8d5b9ae85a1af65eb124 Mon Sep 17 00:00:00 2001 From: Julien Neuhart Date: Tue, 1 Oct 2019 17:33:00 +0200 Subject: [PATCH] office: no more orphan processes (hopefully) --- internal/pkg/printer/office.go | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/internal/pkg/printer/office.go b/internal/pkg/printer/office.go index a395f24c..92ebd7d5 100644 --- a/internal/pkg/printer/office.go +++ b/internal/pkg/printer/office.go @@ -5,6 +5,8 @@ import ( "fmt" "os" "path/filepath" + "strings" + "syscall" "github.com/phayes/freeport" "github.com/thecodingmachine/gotenberg/internal/pkg/conf" @@ -104,8 +106,7 @@ func unoconv(ctx context.Context, logger xlog.Logger, fpath, destination string, args = append(args, "--printer", "PaperOrientation=landscape") } args = append(args, "--output", destination, fpath) - cmd, err := xexec.CommandContext( - ctx, + cmd, err := xexec.Command( logger, "unoconv", args..., @@ -114,7 +115,34 @@ func unoconv(ctx context.Context, logger xlog.Logger, fpath, destination string, return err } xexec.LogBeforeExecute(logger, cmd) - return cmd.Run() + // see https://medium.com/@felixge/killing-a-child-process-and-all-of-its-children-in-go-54079af94773. + kill := func() { + err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + if err == nil { + return + } + if !strings.Contains(err.Error(), "no such process") { + logger.ErrorOp(op, err) + } + } + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + if err := cmd.Start(); err != nil { + return err + } + result := make(chan error, 1) + go func() { + result <- cmd.Wait() + }() + select { + case err := <-result: + logger.DebugfOp(op, "command '%s' finished", strings.Join(cmd.Args, " ")) + kill() + return err + case <-ctx.Done(): + logger.DebugfOp(op, "command '%s' failed to finish before context.Context deadline", strings.Join(cmd.Args, " ")) + kill() + return ctx.Err() + } } if err := resolver(); err != nil { return xerror.New(op, err)