Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 11, 17:15 UTC
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
EINIER FREYRE CORONA committed
Dec 12, 2025 at 12:56 UTC
409a0721354354a2d13e5c110be0f7f03363652b
1 file changed
+64
-5
notify/notify_windows.go
+64
-5
@@ -14,16 +14,26 @@
14
15
package notify
16
17
-import "golang.org/x/sys/windows/svc"
17
+import (
18
+ "log"
19
+ "strings"
20
+
21
+ "golang.org/x/sys/windows/svc"
22
+)
23
24
// globalStatus store windows service status, it can be
25
// use to notify caddy status.
26
var globalStatus chan<- svc.Status
27
28
+// SetGlobalStatus assigns the channel through which status updates
29
+// will be sent to the SCM. This is typically provided by the service
30
+// handler when the service starts.
31
func SetGlobalStatus(status chan<- svc.Status) {
32
globalStatus = status
33
}
34
35
+// Ready notifies the SCM that the service is fully running and ready
36
+// to accept stop or shutdown control requests.
37
func Ready() error {
38
if globalStatus != nil {
39
globalStatus <- svc.Status{
@@ -34,6 +44,8 @@ func Ready() error {
44
return nil
45
}
46
47
+// Reloading notifies the SCM that the service is entering a transitional
48
+// state.
49
func Reloading() error {
50
if globalStatus != nil {
51
globalStatus <- svc.Status{State: svc.StartPending}
@@ -41,6 +53,8 @@ func Reloading() error {
53
return nil
54
}
55
56
+// Stopping notifies the SCM that the service is in the process of stopping.
57
+// This allows Windows to track the shutdown transition properly.
58
func Stopping() error {
59
if globalStatus != nil {
60
globalStatus <- svc.Status{State: svc.StopPending}
@@ -48,8 +62,53 @@ func Stopping() error {
62
return nil
63
}
64
51
-// TODO: not implemented
52
-func Status(_ string) error { return nil }
65
+// Status sends an arbitrary service state to the SCM based on a string
66
+// identifier of [svc.State].
67
+// The unknown states will be logged.
68
+func Status(name string) error {
69
+ if globalStatus == nil {
70
+ return nil
71
+ }
72
+
73
+ var state svc.State
74
+ var accepts svc.Accepted
75
+ accepts = 0
76
+
77
+ switch strings.ToLower(name) {
78
+ case "stopped":
79
+ state = svc.Stopped
80
+ case "start_pending":
81
+ state = svc.StartPending
82
+ case "stop_pending":
83
+ state = svc.StopPending
84
+ case "running":
85
+ state = svc.Running
86
+ accepts = svc.AcceptStop | svc.AcceptShutdown
87
+ case "continue_pending":
88
+ state = svc.ContinuePending
89
+ case "pause_pending":
90
+ state = svc.PausePending
91
+ case "paused":
92
+ state = svc.Paused
93
+ accepts = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue
94
+ default:
95
+ log.Printf("unknown state: %s", name)
96
+ return nil
97
+ }
98
+
99
+ globalStatus <- svc.Status{State: state, Accepts: accepts}
100
+ return nil
101
+}
102
54
-// TODO: not implemented
55
-func Error(_ error, _ int) error { return nil }
103
+// Error notifies the SCM that the service is stopping due to a failure,
104
+// including a service-specific exit code.
105
+func Error(err error, code int) error {
106
+ if globalStatus != nil {
107
+ globalStatus <- svc.Status{
108
+ State: svc.StopPending,
109
+ ServiceSpecificExitCode: uint32(code),
110
+ }
111
+ }
112
+
113
+ return nil
114
+}