From ca712f62a4c39b2b877e555bd2abfe159241a90b Mon Sep 17 00:00:00 2001 From: ulricqin Date: Sun, 6 Jul 2025 08:40:13 +0800 Subject: [PATCH] fix execution of notify script (#2769) --- models/notify_channel.go | 16 +++------------- pkg/cmdx/cmd_notwindows.go | 37 +++++++++++++++++++++++++++++++++++++ pkg/cmdx/cmd_windows.go | 35 +++++++++++++++++++++++++++++++++++ pkg/cmdx/cmdx.go | 15 +++++++++++++++ 4 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 pkg/cmdx/cmd_notwindows.go create mode 100644 pkg/cmdx/cmd_windows.go create mode 100644 pkg/cmdx/cmdx.go diff --git a/models/notify_channel.go b/models/notify_channel.go index 6e1580ea..d3c495cb 100644 --- a/models/notify_channel.go +++ b/models/notify_channel.go @@ -21,10 +21,10 @@ import ( "sort" "strconv" "strings" - "syscall" "time" "unicode/utf8" + "github.com/ccfos/nightingale/v6/pkg/cmdx" "github.com/ccfos/nightingale/v6/pkg/ctx" "github.com/ccfos/nightingale/v6/pkg/poster" "github.com/ccfos/nightingale/v6/pkg/tplx" @@ -33,7 +33,6 @@ import ( "github.com/pkg/errors" "github.com/toolkits/pkg/file" "github.com/toolkits/pkg/logger" - "github.com/toolkits/pkg/sys" "gopkg.in/gomail.v2" ) @@ -196,10 +195,8 @@ func (ncc *NotifyChannelConfig) SendScript(events []*AlertCurEvent, tpl map[stri cmd.Stdout = &buf cmd.Stderr = &buf - err := startCmd(cmd) - if err != nil { - return "", "", fmt.Errorf("failed to start script: %v", err) - } + err, isTimeout := cmdx.RunTimeout(cmd, time.Duration(config.Timeout)*time.Millisecond) + logger.Infof("event_script_notify_result: exec %s output: %s isTimeout: %v err: %v", fpath, buf.String(), isTimeout, err) res := buf.String() @@ -218,8 +215,6 @@ func (ncc *NotifyChannelConfig) SendScript(events []*AlertCurEvent, tpl map[stri res = res[:validLen] + "..." } - err, isTimeout := sys.WrapTimeout(cmd, time.Duration(config.Timeout)*time.Second) - logger.Infof("event_script_notify_result: exec %s output: %s isTimeout: %v err: %v", fpath, buf.String(), isTimeout, err) if isTimeout { if err == nil { return cmd.String(), res, errors.New("timeout and killed process") @@ -257,11 +252,6 @@ func getStdinBytes(events []*AlertCurEvent, tpl map[string]interface{}, params m return jsonBytes } -func startCmd(c *exec.Cmd) error { - c.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - return c.Start() -} - func NotifyChannelStatistics(ctx *ctx.Context) (*Statistics, error) { if !ctx.IsCenter { s, err := poster.GetByUrls[*Statistics](ctx, "/v1/n9e/statistic?name=notify_channel") diff --git a/pkg/cmdx/cmd_notwindows.go b/pkg/cmdx/cmd_notwindows.go new file mode 100644 index 00000000..7a7e204d --- /dev/null +++ b/pkg/cmdx/cmd_notwindows.go @@ -0,0 +1,37 @@ +//go:build !windows +// +build !windows + +package cmdx + +import ( + "os/exec" + "syscall" + "time" +) + +func CmdWait(cmd *exec.Cmd, timeout time.Duration) (error, bool) { + var err error + + done := make(chan error) + go func() { + done <- cmd.Wait() + }() + + select { + case <-time.After(timeout): + go func() { + <-done // allow goroutine to exit + }() + + // IMPORTANT: cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} is necessary before cmd.Start() + err = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + return err, true + case err = <-done: + return err, false + } +} + +func CmdStart(cmd *exec.Cmd) error { + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + return cmd.Start() +} diff --git a/pkg/cmdx/cmd_windows.go b/pkg/cmdx/cmd_windows.go new file mode 100644 index 00000000..4d5e775a --- /dev/null +++ b/pkg/cmdx/cmd_windows.go @@ -0,0 +1,35 @@ +//go:build windows +// +build windows + +package cmdx + +import ( + "os/exec" + "syscall" + "time" +) + +func CmdWait(cmd *exec.Cmd, timeout time.Duration) (error, bool) { + var err error + + done := make(chan error) + go func() { + done <- cmd.Wait() + }() + + select { + case <-time.After(timeout): + go func() { + <-done // allow goroutine to exit + }() + + err = cmd.Process.Signal(syscall.SIGKILL) + return err, true + case err = <-done: + return err, false + } +} + +func CmdStart(cmd *exec.Cmd) error { + return cmd.Start() +} diff --git a/pkg/cmdx/cmdx.go b/pkg/cmdx/cmdx.go new file mode 100644 index 00000000..0a5b8af0 --- /dev/null +++ b/pkg/cmdx/cmdx.go @@ -0,0 +1,15 @@ +package cmdx + +import ( + "os/exec" + "time" +) + +func RunTimeout(cmd *exec.Cmd, timeout time.Duration) (error, bool) { + err := CmdStart(cmd) + if err != nil { + return err, false + } + + return CmdWait(cmd, timeout) +}