Auto-detect and restart daemon on version mismatch (bd-89)
Implements automatic daemon version detection and restart when client and daemon versions are incompatible. Eliminates need for manual 'bd daemon --stop' after upgrades. Changes: - Check daemon version during health check in PersistentPreRun - Auto-restart mismatched daemon or fall back to direct mode - Check version when starting daemon, auto-stop old daemon if incompatible - Robust restart logic: sets working dir, cleans stale sockets, reaps processes - Uses waitForSocketReadiness helper for reliable startup detection - Updated AGENTS.md with version management documentation Closes bd-89 Amp-Thread-ID: https://ampcode.com/threads/T-231a3701-c9c8-49e4-a1b0-e67c94e5c365 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -90,9 +90,32 @@ Use --health to check daemon health and metrics.`,
|
||||
|
||||
// Check if daemon is already running
|
||||
if isRunning, pid := isDaemonRunning(pidFile); isRunning {
|
||||
fmt.Fprintf(os.Stderr, "Error: daemon already running (PID %d)\n", pid)
|
||||
fmt.Fprintf(os.Stderr, "Use 'bd daemon --stop%s' to stop it first\n", boolToFlag(global, " --global"))
|
||||
os.Exit(1)
|
||||
// Check if running daemon has compatible version
|
||||
socketPath := getSocketPathForPID(pidFile, global)
|
||||
if client, err := rpc.TryConnectWithTimeout(socketPath, 1*time.Second); err == nil && client != nil {
|
||||
health, healthErr := client.Health()
|
||||
client.Close()
|
||||
|
||||
// If we can check version and it's compatible, exit
|
||||
if healthErr == nil && health.Compatible {
|
||||
fmt.Fprintf(os.Stderr, "Error: daemon already running (PID %d, version %s)\n", pid, health.Version)
|
||||
fmt.Fprintf(os.Stderr, "Use 'bd daemon --stop%s' to stop it first\n", boolToFlag(global, " --global"))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Version mismatch - auto-stop old daemon
|
||||
if healthErr == nil && !health.Compatible {
|
||||
fmt.Fprintf(os.Stderr, "Warning: daemon version mismatch (daemon: %s, client: %s)\n", health.Version, Version)
|
||||
fmt.Fprintf(os.Stderr, "Stopping old daemon and starting new one...\n")
|
||||
stopDaemon(pidFile)
|
||||
// Continue with daemon startup
|
||||
}
|
||||
} else {
|
||||
// Can't check version - assume incompatible
|
||||
fmt.Fprintf(os.Stderr, "Error: daemon already running (PID %d)\n", pid)
|
||||
fmt.Fprintf(os.Stderr, "Use 'bd daemon --stop%s' to stop it first\n", boolToFlag(global, " --global"))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Global daemon doesn't support auto-commit/auto-push (no sync loop)
|
||||
@@ -220,6 +243,16 @@ func getEnvBool(key string, defaultValue bool) bool {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// getSocketPathForPID determines the socket path for a given PID file
|
||||
func getSocketPathForPID(pidFile string, global bool) string {
|
||||
if global {
|
||||
home, _ := os.UserHomeDir()
|
||||
return filepath.Join(home, ".beads", "bd.sock")
|
||||
}
|
||||
// Local daemon: socket is in same directory as PID file
|
||||
return filepath.Join(filepath.Dir(pidFile), "bd.sock")
|
||||
}
|
||||
|
||||
func getPIDFilePath(global bool) (string, error) {
|
||||
var beadsDir string
|
||||
var err error
|
||||
|
||||
Reference in New Issue
Block a user