From 998c49e52dd85107273e9a945209fd70fe470acd Mon Sep 17 00:00:00 2001 From: Vishnuvardhan Reddy Date: Tue, 24 Feb 2026 18:24:29 +0000 Subject: [PATCH] fix: write correct child process PID to PID file The Write() method was using os.Getpid() which writes the parent's PID instead of the spawned child process PID. Added WritePID() method to explicitly write a specific PID and added process verification after spawn. --- pkg/daemon/pidfile.go | 18 ++++++++++++------ pkg/daemon/service.go | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/pkg/daemon/pidfile.go b/pkg/daemon/pidfile.go index 0ee026c59..a68f3356b 100644 --- a/pkg/daemon/pidfile.go +++ b/pkg/daemon/pidfile.go @@ -44,24 +44,30 @@ func NewPIDFile(path string) *PIDFile { // This prevents multiple instances of the gateway from running simultaneously, // which could cause resource conflicts and undefined behavior. func (p *PIDFile) Write() error { + return p.WritePID(os.Getpid()) +} + +// WritePID atomically writes the specified process ID to the PID file. +// Returns an error if a PID file already exists with a running process. +// +// Use this method when you need to write a PID other than the current process, +// such as when spawning a child process. +func (p *PIDFile) WritePID(pid int) error { p.mu.Lock() defer p.mu.Unlock() // Check for existing PID file if _, err := os.Stat(p.path); err == nil { // PID file exists, check if process is running - pid, err := p.read() - if err == nil && p.isProcessRunning(pid) { + existingPid, err := p.read() + if err == nil && p.isProcessRunning(existingPid) { return &ProcessRunningError{ - pid: pid, + pid: existingPid, Path: p.path, } } // Process is not running, stale PID file, continue } - - // Write PID to temp file in same directory (atomic preparation) - pid := os.Getpid() pidStr := strconv.Itoa(pid) tempFile := p.path + ".tmp" diff --git a/pkg/daemon/service.go b/pkg/daemon/service.go index 1dd95ec28..b91cbb39c 100644 --- a/pkg/daemon/service.go +++ b/pkg/daemon/service.go @@ -150,14 +150,24 @@ func (s *Service) Start() error { pid := cmd.Process.Pid - // Write PID file atomically - if err := s.pidFile.Write(); err != nil { + // Write PID file atomically with the child's PID + if err := s.pidFile.WritePID(pid); err != nil { // Failed to write PID file, kill the process cmd.Process.Kill() logFile.Close() return fmt.Errorf("failed to write PID file: %w", err) } + // Verify the child process is actually running + // This prevents race conditions where status is checked immediately + time.Sleep(100 * time.Millisecond) + if !s.pidFile.IsProcessRunning() { + // Child process died immediately, likely a startup error + s.pidFile.Remove() + logFile.Close() + return fmt.Errorf("gateway process failed to start (check log file: %s)", s.logConfig.Path) + } + // Update state s.state.SetPID(pid) s.state.SetStartTime(time.Now())