mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-30 17:49:40 +09:00
fix(process): reap entire process group on cmd.Cancel (#39143)
Signed-off-by: Royce Remer <royceremer@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
co-authored by
wxiaoguang
parent
88974d2db9
commit
eea03676d3
@@ -0,0 +1,54 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package process
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
type Cmd struct {
|
||||
*exec.Cmd
|
||||
|
||||
onCancelUserFunc func() error
|
||||
termGraceful bool
|
||||
}
|
||||
|
||||
func (c *Cmd) WithOnCancelGracefully(userFunc func() error) *Cmd {
|
||||
c.termGraceful, c.onCancelUserFunc = true, userFunc
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Cmd) WithOnCancelForceKill(userFunc func() error) *Cmd {
|
||||
c.termGraceful, c.onCancelUserFunc = false, userFunc
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Cmd) WithDir(dir string) *Cmd {
|
||||
c.Cmd.Dir = dir
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Cmd) OutputString() (string, string, error) {
|
||||
stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
|
||||
c.Cmd.Stdout = stdout
|
||||
c.Cmd.Stderr = stderr
|
||||
err := c.Cmd.Run()
|
||||
return stdout.String(), stderr.String(), err
|
||||
}
|
||||
|
||||
// CommandContext returns a wrapped exec.Cmd which kills the process group when the context is canceled.
|
||||
// By default, it uses graceful termination (SIGTERM) on Unix-like systems to make the subprocesses have chances
|
||||
// to clean up (e.g. remove temporary files or lock files).
|
||||
func CommandContext(ctx context.Context, name string, arg ...string) *Cmd {
|
||||
c := &Cmd{Cmd: exec.CommandContext(ctx, name, arg...)} //nolint:forbidigo // wrap it
|
||||
setSysProcAttribute(c.Cmd)
|
||||
c.Cmd.Cancel = c.onCancel
|
||||
|
||||
// Unlike exec.CommandContext, we use graceful termination by default to avoid corrupting data or leaving lock files behind.
|
||||
// If some processes don't respond to SIGTERM, can switch to WithOnCancelForceKill (SIGKILL) to force kill them.
|
||||
c.termGraceful = true
|
||||
return c
|
||||
}
|
||||
Reference in New Issue
Block a user