Files
beads/cmd/bd/daemon_server.go
Steve Yegge f3e1268b33 refactor: remove deprecated global daemon support
Global daemon support has been deprecated for most of the project's
lifetime. This change removes the dead code entirely:

- Remove --global and --migrate-to-global daemon flags
- Remove runGlobalDaemon() and migrateToGlobalDaemon() functions
- Remove shouldUseGlobalDaemon() and getGlobalBeadsDir() functions
- Simplify functions that had global bool parameters
- Remove warning about old global socket in getSocketPath()

This reduces code complexity and removes 238 net lines of unused code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 23:39:54 -08:00

115 lines
3.2 KiB
Go

package main
import (
"context"
"os"
"os/signal"
"time"
"github.com/steveyegge/beads/internal/rpc"
"github.com/steveyegge/beads/internal/storage"
)
// startRPCServer initializes and starts the RPC server
func startRPCServer(ctx context.Context, socketPath string, store storage.Storage, workspacePath string, dbPath string, log daemonLogger) (*rpc.Server, chan error, error) {
// Sync daemon version with CLI version
rpc.ServerVersion = Version
server := rpc.NewServer(socketPath, store, workspacePath, dbPath)
serverErrChan := make(chan error, 1)
go func() {
log.log("Starting RPC server: %s", socketPath)
if err := server.Start(ctx); err != nil {
log.log("RPC server error: %v", err)
serverErrChan <- err
}
}()
select {
case err := <-serverErrChan:
log.log("RPC server failed to start: %v", err)
return nil, nil, err
case <-server.WaitReady():
log.log("RPC server ready (socket listening)")
case <-time.After(5 * time.Second):
log.log("WARNING: Server didn't signal ready after 5 seconds (may still be starting)")
}
return server, serverErrChan, nil
}
// checkParentProcessAlive checks if the parent process is still running.
// Returns true if parent is alive, false if it died.
// Returns true if parent PID is 0 or 1 (not tracked, or adopted by init).
func checkParentProcessAlive(parentPID int) bool {
if parentPID == 0 {
// Parent PID not tracked (older lock files)
return true
}
if parentPID == 1 {
// Adopted by init/launchd - this is normal for detached daemons on macOS/Linux
// Don't treat this as parent death
return true
}
// Check if parent process is running
return isProcessRunning(parentPID)
}
// runEventLoop runs the daemon event loop (polling mode)
func runEventLoop(ctx context.Context, cancel context.CancelFunc, ticker *time.Ticker, doSync func(), server *rpc.Server, serverErrChan chan error, parentPID int, log daemonLogger) {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, daemonSignals...)
defer signal.Stop(sigChan)
// Parent process check (every 10 seconds)
parentCheckTicker := time.NewTicker(10 * time.Second)
defer parentCheckTicker.Stop()
for {
select {
case <-ticker.C:
if ctx.Err() != nil {
return
}
doSync()
case <-parentCheckTicker.C:
// Check if parent process is still alive
if !checkParentProcessAlive(parentPID) {
log.log("Parent process (PID %d) died, shutting down daemon", parentPID)
cancel()
if err := server.Stop(); err != nil {
log.log("Error stopping server: %v", err)
}
return
}
case sig := <-sigChan:
if isReloadSignal(sig) {
log.log("Received reload signal, ignoring (daemon continues running)")
continue
}
log.log("Received signal %v, shutting down gracefully...", sig)
cancel()
if err := server.Stop(); err != nil {
log.log("Error stopping RPC server: %v", err)
}
return
case <-ctx.Done():
log.log("Context canceled, shutting down")
if err := server.Stop(); err != nil {
log.log("Error stopping RPC server: %v", err)
}
return
case err := <-serverErrChan:
log.log("RPC server failed: %v", err)
cancel()
if err := server.Stop(); err != nil {
log.log("Error stopping RPC server: %v", err)
}
return
}
}
}