From bf22d6f47925cd213aee5a5be72ea1b4c03da993 Mon Sep 17 00:00:00 2001 From: criyle Date: Tue, 28 Oct 2025 16:27:13 +0000 Subject: [PATCH] feat(main): ignoring SIGTERM when managed by PM2 - there is a race condition during shutting down when go-judge receives SIGTERM from systemd and PM2 dumps a STOPPED status, resulting go-judge not auto-restart after a reboot - PM2 uses SIGINT for stop signal so that we can distinguish different stop signal sent by different process manager - So when detected that we are manged by PM2, we ignore the SIGTERM signal from the systemd and wait for PM2's SIGINT to avoid race condition Unitech/pm2#6036 --- cmd/go-judge/main.go | 34 +++++++++++++++++++++++++++++++--- env/env_cgroup_linux.go | 1 + 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/cmd/go-judge/main.go b/cmd/go-judge/main.go index 427a433..c143fd7 100644 --- a/cmd/go-judge/main.go +++ b/cmd/go-judge/main.go @@ -16,6 +16,7 @@ import ( "runtime" "runtime/debug" "strings" + "syscall" "time" "github.com/criyle/go-judge/cmd/go-judge/config" @@ -106,9 +107,21 @@ func main() { newForceGCWorker(conf) // Graceful shutdown... - signal.Notify(sig, os.Interrupt) - <-sig - signal.Reset(os.Interrupt) + signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) +loop: + for s := range sig { + switch s { + case syscall.SIGINT: + break loop + case syscall.SIGTERM: + if isManagedByPM2() { + logger.Info("running with PM2, received SIGTERM (from systemd), ignoring") + } else { + break loop + } + } + } + signal.Reset(syscall.SIGINT, syscall.SIGTERM) logger.Info("Shutting Down...") @@ -591,3 +604,18 @@ func generateHandleConfig(conf *config.Config, builderParam map[string]any) func }) } } + +func isManagedByPM2() bool { + // List of environment variables that pm2 typically sets. + pm2EnvVars := []string{ + "PM2_HOME", + "PM2_JSON_PROCESSING", + "NODE_APP_INSTANCE", + } + for _, v := range pm2EnvVars { + if os.Getenv(v) != "" { + return true + } + } + return false +} diff --git a/env/env_cgroup_linux.go b/env/env_cgroup_linux.go index 813c2f7..5b418a6 100644 --- a/env/env_cgroup_linux.go +++ b/env/env_cgroup_linux.go @@ -76,6 +76,7 @@ func startTransientUnit(conn *dbus.Conn, scopeName string, logger *zap.Logger) e dbus.PropWants(scopeName), dbus.PropPids(uint32(os.Getpid())), newSystemdProperty("Delegate", true), + newSystemdProperty("KillMode", "process"), } ch := make(chan string, 1) if _, err := conn.StartTransientUnitContext(context.TODO(), scopeName, "replace", properties, ch); err != nil {