@@ -10,7 +10,9 @@ import (
1010 "os"
1111 "path/filepath"
1212 "sort"
13+ "strconv"
1314 "strings"
15+ "syscall"
1416 "time"
1517
1618 "github.com/coder/agentapi/lib/screentracker"
@@ -268,6 +270,19 @@ func writePIDFile(pidFile string, logger *slog.Logger) error {
268270 return xerrors .Errorf ("failed to create PID file directory: %w" , err )
269271 }
270272
273+ // Check if PID file already exists
274+ if existingPIDData , err := os .ReadFile (pidFile ); err == nil {
275+ existingPIDStr := strings .TrimSpace (string (existingPIDData ))
276+ if existingPID , err := strconv .Atoi (existingPIDStr ); err == nil {
277+ if isProcessRunning (existingPID ) {
278+ return xerrors .Errorf ("another instance is already running with PID %d (PID file: %s)" , existingPID , pidFile )
279+ }
280+ logger .Warn ("Found stale PID file, will overwrite" , "pidFile" , pidFile , "stalePID" , existingPID )
281+ }
282+ } else if ! os .IsNotExist (err ) {
283+ return xerrors .Errorf ("failed to read existing PID file: %w" , err )
284+ }
285+
271286 // Write PID file
272287 if err := os .WriteFile (pidFile , []byte (pidContent ), 0o600 ); err != nil {
273288 return xerrors .Errorf ("failed to write PID file: %w" , err )
@@ -286,6 +301,16 @@ func cleanupPIDFile(pidFile string, logger *slog.Logger) {
286301 }
287302}
288303
304+ // isProcessRunning checks if a process with the given PID is running
305+ func isProcessRunning (pid int ) bool {
306+ process , err := os .FindProcess (pid )
307+ if err != nil {
308+ return false
309+ }
310+ err = process .Signal (syscall .Signal (0 ))
311+ return err == nil || errors .Is (err , syscall .EPERM )
312+ }
313+
289314type flagSpec struct {
290315 name string
291316 shorthand string
0 commit comments