The service package now has a Linux implementation alongside the Windows one: systemd unit install/remove (/etc/systemd/system), readiness notification (READY=1 via go-systemd) sent only after the listeners are bound, a 30s watchdog, and STOPPING on shutdown. Listeners are pre-bound so port conflicts fail fast and the readiness signal is truthful. The notify calls are no-ops without NOTIFY_SOCKET (containers, shells) and on non-Linux builds. --install-service/--remove-service work on both platforms; the 'service install|remove' subcommand remains as an alias.
47 lines
1.1 KiB
Go
47 lines
1.1 KiB
Go
//go:build linux
|
|
|
|
package service
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/coreos/go-systemd/v22/daemon"
|
|
)
|
|
|
|
// NotifyReady tells systemd the service is up (Type=notify). It is a no-op
|
|
// when NOTIFY_SOCKET is unset, e.g. in a container or interactive shell.
|
|
func NotifyReady() {
|
|
daemon.SdNotify(false, daemon.SdNotifyReady)
|
|
}
|
|
|
|
// NotifyStopping tells systemd the service is shutting down.
|
|
func NotifyStopping() {
|
|
daemon.SdNotify(false, daemon.SdNotifyStopping)
|
|
}
|
|
|
|
// StartWatchdog pings the systemd watchdog every half of WATCHDOG_USEC
|
|
// until ctx is cancelled. It is a no-op unless systemd started the process
|
|
// with a watchdog configured (WatchdogSec= in the unit).
|
|
func StartWatchdog(ctx context.Context) {
|
|
usec, err := strconv.Atoi(os.Getenv("WATCHDOG_USEC"))
|
|
if err != nil || usec <= 0 {
|
|
return
|
|
}
|
|
interval := time.Duration(usec) * time.Microsecond / 2
|
|
go func() {
|
|
ticker := time.NewTicker(interval)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
daemon.SdNotify(false, daemon.SdNotifyWatchdog)
|
|
}
|
|
}
|
|
}()
|
|
}
|