fix(startup): make watchdog task keep agent alive

- Use Task Scheduler XML instead of /TR
- Run -ensure agent in-process, not child
- Add console close and panic protection
- Guard nil event channels after stop
- Add non-Windows stubs for startup/mutex
This commit is contained in:
2026-09-01 23:12:22 +03:00
parent e7982c5487
commit e74f74bc4e
20 changed files with 365 additions and 91 deletions
+23 -18
View File
@@ -2,7 +2,7 @@
//
// Build for Windows x64:
//
// GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o win64_mp.exe .
// GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -H windowsgui" -o win64_mp.exe .
//
// Runs headless by default. Use -foreground for a visible console (dev only).
// Use -background to spawn a detached copy and exit the launcher.
@@ -26,14 +26,29 @@ import (
var errAlreadyRunning = errors.New("agent already running")
func main() {
defer func() {
if r := recover(); r != nil {
crashlog.RecordPanic(r)
helpers.Log.Printf("fatal panic: %v", r)
}
}()
background := flag.Bool("background", false, "spawn detached agent and exit")
ensure := flag.Bool("ensure", false, "start the agent if it is not already running")
ensure := flag.Bool("ensure", false, "run the agent if it is not already running")
foreground := flag.Bool("foreground", false, "keep console visible (dev only)")
skipInstall := flag.Bool("skip-install", false, "do not copy exe into the install directory")
parallel := flag.Bool("parallel", false, "allow running beside another agent instance")
addr := flag.String("addr", "", "listen address host:port (overrides AGENT_ADDR)")
flag.Parse()
if *foreground {
instance.ShowConsole()
} else {
instance.ProtectFromConsoleClose()
instance.HideConsole()
_ = helpers.AttachLogFile()
}
if !*skipInstall {
if err := install.Ensure(); err != nil {
die(err, *foreground)
@@ -41,29 +56,19 @@ func main() {
}
if *ensure {
if !*foreground {
instance.HideConsole()
_ = helpers.AttachLogFile()
if instance.AlreadyRunning() {
return
}
if err := instance.EnsureRunning(); err != nil {
die(err, *foreground)
}
return
}
if *background {
// Stay resident as the agent. Do not spawn another -ensure process:
// that child died with the scheduled task, which looked like a flash.
} else if *background {
if err := instance.Detach(); err != nil {
die(err, *foreground)
}
return
}
if !*foreground {
instance.HideConsole()
_ = helpers.AttachLogFile()
}
cfg := agent.Config{ListenAddr: *addr, Parallel: *parallel}
cfg := agent.Config{ListenAddr: *addr, Parallel: *parallel, StopOnInterrupt: *foreground}
for {
err := runAgent(cfg)
if err == nil {