Files
zzet--gortex/cmd/gortex/daemon_supervisor.go
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

108 lines
3.7 KiB
Go

package main
import (
"fmt"
"io"
"os"
"os/exec"
"runtime"
"strings"
)
// Supervisor-aware stop / restart.
//
// When the daemon is owned by an OS supervisor installed via
// `gortex daemon install-service` (systemd --user on Linux, launchd on macOS),
// a plain socket-level `daemon stop` just kills the worker — and the supervisor
// promptly restarts it (launchd KeepAlive; systemd on a non-clean exit). So
// when a supervisor owns the daemon we drive the lifecycle THROUGH it:
//
// - stop → tell the supervisor to stop the unit (stays installed/enabled),
// - restart → tell the supervisor to bounce the unit, keeping its ownership.
//
// A manual stop+start under a supervisor would orphan the freshly-started
// daemon from the unit (the unit reads inactive while a hand-started process
// holds the socket), so restart must route through the supervisor too.
//
// The three entry points are function vars so the routing in runDaemonStop /
// runDaemonRestart is testable without a real systemd / launchd.
var (
serviceActive = defaultServiceActive
serviceStop = defaultServiceStop
serviceRestart = defaultServiceRestart
)
// defaultServiceActive reports whether an installed service unit currently owns
// the daemon (unit file present AND the supervisor reports it active/loaded).
// It short-circuits on a missing unit file so the common, unsupervised case
// never shells out.
func defaultServiceActive() bool {
switch runtime.GOOS {
case "linux":
path, err := systemdUnitPath()
if err != nil {
return false
}
if _, err := os.Stat(path); err != nil {
return false
}
out, _ := exec.Command("systemctl", "--user", "is-active", daemonServiceName).Output()
return strings.TrimSpace(string(out)) == "active"
case "darwin":
path, err := launchdPlistPath()
if err != nil {
return false
}
if _, err := os.Stat(path); err != nil {
return false
}
// `launchctl list <label>` exits 0 when the agent is loaded.
return exec.Command("launchctl", "list", daemonServiceName).Run() == nil
default:
return false
}
}
// defaultServiceStop stops the daemon via its supervisor so it stays down — the
// unit remains installed/enabled and comes back at next login or an explicit
// `daemon start`.
func defaultServiceStop(w io.Writer) error {
switch runtime.GOOS {
case "linux":
if err := runCmd(w, "systemctl", "--user", "stop", daemonServiceName); err != nil {
return fmt.Errorf("systemctl --user stop: %w", err)
}
case "darwin":
// bootout stops + unloads for this login session; KeepAlive can't
// resurrect a booted-out agent. RunAtLoad reloads it at next login.
label := fmt.Sprintf("gui/%d/%s", os.Getuid(), daemonServiceName)
if err := runCmd(w, "launchctl", "bootout", label); err != nil {
return fmt.Errorf("launchctl bootout: %w", err)
}
default:
return fmt.Errorf("supervised stop not supported on %s", runtime.GOOS)
}
fmt.Fprintln(w, "[gortex daemon] stopped via service supervisor")
return nil
}
// defaultServiceRestart bounces the daemon through its supervisor so the
// supervisor keeps owning the new process.
func defaultServiceRestart(w io.Writer) error {
switch runtime.GOOS {
case "linux":
if err := runCmd(w, "systemctl", "--user", "restart", daemonServiceName); err != nil {
return fmt.Errorf("systemctl --user restart: %w", err)
}
case "darwin":
label := fmt.Sprintf("gui/%d/%s", os.Getuid(), daemonServiceName)
if err := runCmd(w, "launchctl", "kickstart", "-k", label); err != nil {
return fmt.Errorf("launchctl kickstart -k: %w", err)
}
default:
return fmt.Errorf("supervised restart not supported on %s", runtime.GOOS)
}
fmt.Fprintln(w, "[gortex daemon] restarted via service supervisor")
return nil
}