Additional Windows CI fixes (bd-99)

- Write PID to daemon.pid when acquiring lock for Windows compatibility
- Increase socket cleanup timeout to 5s for Windows
- Windows can't read locked files, so PID file is required fallback
This commit is contained in:
Steve Yegge
2025-10-24 10:12:59 -07:00
parent 09e51b2184
commit 42480014b3
3 changed files with 13 additions and 9 deletions
+8 -8
View File
@@ -94,7 +94,7 @@ Use --health to check daemon health and metrics.`,
socketPath := getSocketPathForPID(pidFile, global) socketPath := getSocketPathForPID(pidFile, global)
if client, err := rpc.TryConnectWithTimeout(socketPath, 1*time.Second); err == nil && client != nil { if client, err := rpc.TryConnectWithTimeout(socketPath, 1*time.Second); err == nil && client != nil {
health, healthErr := client.Health() health, healthErr := client.Health()
client.Close() _ = client.Close()
// If we can check version and it's compatible, exit // If we can check version and it's compatible, exit
if healthErr == nil && health.Compatible { if healthErr == nil && health.Compatible {
@@ -364,7 +364,7 @@ func showDaemonHealth(global bool) {
fmt.Println("Daemon is not running") fmt.Println("Daemon is not running")
os.Exit(1) os.Exit(1)
} }
defer client.Close() defer func() { _ = client.Close() }()
health, err := client.Health() health, err := client.Health()
if err != nil { if err != nil {
@@ -430,7 +430,7 @@ func showDaemonMetrics(global bool) {
fmt.Println("Daemon is not running") fmt.Println("Daemon is not running")
os.Exit(1) os.Exit(1)
} }
defer client.Close() defer func() { _ = client.Close() }()
metrics, err := client.Metrics() metrics, err := client.Metrics()
if err != nil { if err != nil {
@@ -647,7 +647,7 @@ func startDaemon(interval time.Duration, autoCommit, autoPush bool, logFile, pid
fmt.Fprintf(os.Stderr, "Error opening /dev/null: %v\n", err) fmt.Fprintf(os.Stderr, "Error opening /dev/null: %v\n", err)
os.Exit(1) os.Exit(1)
} }
defer devNull.Close() defer func() { _ = devNull.Close() }()
cmd.Stdin = devNull cmd.Stdin = devNull
cmd.Stdout = devNull cmd.Stdout = devNull
@@ -730,9 +730,9 @@ func exportToJSONLWithStore(ctx context.Context, store storage.Storage, jsonlPat
// Use defer pattern for proper cleanup // Use defer pattern for proper cleanup
var writeErr error var writeErr error
defer func() { defer func() {
tempFile.Close() _ = tempFile.Close()
if writeErr != nil { if writeErr != nil {
os.Remove(tempPath) // Remove temp file on error _ = os.Remove(tempPath) // Remove temp file on error
} }
}() }()
@@ -793,12 +793,12 @@ func runDaemonLoop(interval time.Duration, autoCommit, autoPush bool, logPath, p
MaxAge: maxAgeDays, // days MaxAge: maxAgeDays, // days
Compress: compress, // compress old logs Compress: compress, // compress old logs
} }
defer logF.Close() defer func() { _ = logF.Close() }()
log := func(format string, args ...interface{}) { log := func(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...) msg := fmt.Sprintf(format, args...)
timestamp := time.Now().Format("2006-01-02 15:04:05") timestamp := time.Now().Format("2006-01-02 15:04:05")
fmt.Fprintf(logF, "[%s] %s\n", timestamp, msg) _, _ = fmt.Fprintf(logF, "[%s] %s\n", timestamp, msg)
} }
// Acquire daemon lock FIRST - this is the single source of truth for exclusivity // Acquire daemon lock FIRST - this is the single source of truth for exclusivity
+4
View File
@@ -54,6 +54,10 @@ func acquireDaemonLock(beadsDir string, global bool) (*DaemonLock, error) {
fmt.Fprintf(f, "%d\n", os.Getpid()) fmt.Fprintf(f, "%d\n", os.Getpid())
_ = f.Sync() _ = f.Sync()
// Also write PID file for Windows compatibility (can't read locked files on Windows)
pidFile := filepath.Join(beadsDir, "daemon.pid")
_ = os.WriteFile(pidFile, []byte(fmt.Sprintf("%d\n", os.Getpid())), 0644)
return &DaemonLock{file: f, path: lockPath}, nil return &DaemonLock{file: f, path: lockPath}, nil
} }
+1 -1
View File
@@ -264,7 +264,7 @@ func (s *Server) Stop() error {
select { select {
case <-s.doneChan: case <-s.doneChan:
// Cleanup completed // Cleanup completed
case <-time.After(2 * time.Second): case <-time.After(5 * time.Second):
// Timeout waiting for cleanup - continue anyway // Timeout waiting for cleanup - continue anyway
} }