notify: implement windows service status and error notifications (#7389)

* implement service status and error notifications

* adjust return of Error function

* configure accepts on status

* align windows with linux semantics
This commit is contained in:
EINIER FREYRE CORONA
2025-12-12 12:56:30 +00:00
committed by GitHub
parent 6a4296b1a4
commit 409a072135

View File

@@ -14,16 +14,26 @@
package notify
import "golang.org/x/sys/windows/svc"
import (
"log"
"strings"
"golang.org/x/sys/windows/svc"
)
// globalStatus store windows service status, it can be
// use to notify caddy status.
var globalStatus chan<- svc.Status
// SetGlobalStatus assigns the channel through which status updates
// will be sent to the SCM. This is typically provided by the service
// handler when the service starts.
func SetGlobalStatus(status chan<- svc.Status) {
globalStatus = status
}
// Ready notifies the SCM that the service is fully running and ready
// to accept stop or shutdown control requests.
func Ready() error {
if globalStatus != nil {
globalStatus <- svc.Status{
@@ -34,6 +44,8 @@ func Ready() error {
return nil
}
// Reloading notifies the SCM that the service is entering a transitional
// state.
func Reloading() error {
if globalStatus != nil {
globalStatus <- svc.Status{State: svc.StartPending}
@@ -41,6 +53,8 @@ func Reloading() error {
return nil
}
// Stopping notifies the SCM that the service is in the process of stopping.
// This allows Windows to track the shutdown transition properly.
func Stopping() error {
if globalStatus != nil {
globalStatus <- svc.Status{State: svc.StopPending}
@@ -48,8 +62,53 @@ func Stopping() error {
return nil
}
// TODO: not implemented
func Status(_ string) error { return nil }
// Status sends an arbitrary service state to the SCM based on a string
// identifier of [svc.State].
// The unknown states will be logged.
func Status(name string) error {
if globalStatus == nil {
return nil
}
// TODO: not implemented
func Error(_ error, _ int) error { return nil }
var state svc.State
var accepts svc.Accepted
accepts = 0
switch strings.ToLower(name) {
case "stopped":
state = svc.Stopped
case "start_pending":
state = svc.StartPending
case "stop_pending":
state = svc.StopPending
case "running":
state = svc.Running
accepts = svc.AcceptStop | svc.AcceptShutdown
case "continue_pending":
state = svc.ContinuePending
case "pause_pending":
state = svc.PausePending
case "paused":
state = svc.Paused
accepts = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue
default:
log.Printf("unknown state: %s", name)
return nil
}
globalStatus <- svc.Status{State: state, Accepts: accepts}
return nil
}
// Error notifies the SCM that the service is stopping due to a failure,
// including a service-specific exit code.
func Error(err error, code int) error {
if globalStatus != nil {
globalStatus <- svc.Status{
State: svc.StopPending,
ServiceSpecificExitCode: uint32(code),
}
}
return nil
}