-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontrols.go
More file actions
263 lines (227 loc) · 7.7 KB
/
Copy pathcontrols.go
File metadata and controls
263 lines (227 loc) · 7.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
package controls
import (
"context"
"log/slog"
"os"
"sync"
"time"
)
// CheckStatus represents the health state of a check.
type CheckStatus int
const (
// CheckHealthy indicates the check passed.
CheckHealthy CheckStatus = iota
// CheckDegraded indicates the check passed but with warnings.
// Maps to OverallHealthy: true with Status: "DEGRADED".
CheckDegraded
// CheckUnhealthy indicates the check failed.
// Maps to OverallHealthy: false with Status: "ERROR".
CheckUnhealthy
)
// CheckResult represents the outcome of a health check.
type CheckResult struct {
// Status is the health status.
Status CheckStatus
// Message provides human-readable detail about the check result.
Message string
// Timestamp is when this result was produced.
Timestamp time.Time
}
// CheckType determines which health endpoint(s) a check contributes to.
type CheckType int
const (
// CheckTypeReadiness contributes to the readiness endpoint.
CheckTypeReadiness CheckType = iota
// CheckTypeLiveness contributes to the liveness endpoint.
CheckTypeLiveness
// CheckTypeBoth contributes to both liveness and readiness endpoints.
CheckTypeBoth
)
// HealthCheck defines a named health check function.
type HealthCheck struct {
// Name is the unique identifier for this check.
Name string
// Check is the function that performs the health check.
// It receives a context with the check's timeout applied.
Check func(ctx context.Context) CheckResult
// Timeout is the maximum duration for a single check execution.
// Default: 5s.
Timeout time.Duration
// Interval is the polling interval for async checks.
// Zero means synchronous (run on every health request).
Interval time.Duration
// Type determines which health endpoints this check feeds into.
// Default: CheckTypeReadiness.
Type CheckType
}
const (
Stop Message = "stop"
)
const (
Unknown State = "unknown"
Running State = "running"
Stopping State = "stopping"
Stopped State = "stopped"
)
// State represents the lifecycle state of the controller (Unknown, Running, Stopping, Stopped).
type State string
// Message represents a control message sent to the controller (e.g. "stop").
type Message string
// StartFunc is the callback invoked to start a service. It receives a context
// that is cancelled when the controller shuts down.
type StartFunc func(context.Context) error
// StopFunc is the callback invoked to stop a service gracefully. The context
// carries the shutdown timeout.
type StopFunc func(context.Context)
// StatusFunc is the callback invoked to check a service's health.
// Returns nil if healthy, an error otherwise.
type StatusFunc func() error
// ProbeFunc is a health check function for liveness or readiness probes.
type ProbeFunc func() error
// ValidErrorFunc determines whether an error from a service is expected
// (e.g. http.ErrServerClosed) and should not trigger a restart.
type ValidErrorFunc func(error) bool
// ServiceOption is a functional option for configuring a Service.
type ServiceOption func(*Service)
// WithStart sets the service's start function.
func WithStart(fn StartFunc) ServiceOption {
return func(s *Service) {
s.Start = fn
}
}
// WithStop sets the service's graceful shutdown function.
func WithStop(fn StopFunc) ServiceOption {
return func(s *Service) {
s.Stop = fn
}
}
// WithStatus sets the service's health check function.
func WithStatus(fn StatusFunc) ServiceOption {
return func(s *Service) {
s.Status = fn
}
}
// WithLiveness sets a liveness probe for the service.
func WithLiveness(fn ProbeFunc) ServiceOption {
return func(s *Service) {
s.Liveness = fn
}
}
// WithReadiness sets a readiness probe for the service.
func WithReadiness(fn ProbeFunc) ServiceOption {
return func(s *Service) {
s.Readiness = fn
}
}
// RestartPolicy defines how a service should be restarted on failure.
type RestartPolicy struct {
MaxRestarts int
InitialBackoff time.Duration
MaxBackoff time.Duration
HealthFailureThreshold int
HealthCheckInterval time.Duration
// RestartResetInterval is how long a service must run healthily before its
// consecutive-failure restart counter is reset to zero. Zero selects
// DefaultRestartResetInterval. The count therefore measures consecutive
// failures, not lifetime restarts.
RestartResetInterval time.Duration
}
// WithRestartPolicy configures automatic restart behaviour for a service.
func WithRestartPolicy(policy RestartPolicy) ServiceOption {
return func(s *Service) {
s.RestartPolicy = &policy
}
}
// WithRestartResetInterval sets how long a service must run healthily before its
// consecutive-failure restart counter resets. It implies a restart policy: if
// the service has none, a default policy is created so the interval takes effect.
func WithRestartResetInterval(d time.Duration) ServiceOption {
return func(s *Service) {
if s.RestartPolicy == nil {
s.RestartPolicy = &RestartPolicy{}
}
s.RestartPolicy.RestartResetInterval = d
}
}
// ServiceInfo holds runtime metadata about a registered service.
type ServiceInfo struct {
Name string
RestartCount int
LastStarted time.Time
LastStopped time.Time
Error error
}
// ServiceStatus is the health status of a single service, used in HealthReport.
type ServiceStatus struct {
Name string `json:"name"`
Status string `json:"status"` // "OK", "ERROR"
Error string `json:"error,omitempty"`
}
// HealthReport is the aggregate health status across all registered services.
type HealthReport struct {
OverallHealthy bool `json:"overall_healthy"`
Services []ServiceStatus `json:"services"`
}
// Runner provides service lifecycle operations.
type Runner interface {
Start()
Stop()
IsRunning() bool
IsStopped() bool
IsStopping() bool
Register(id string, opts ...ServiceOption)
}
// HealthReporter provides read access to service health, liveness, and readiness
// reports, and to per-service runtime information. Handlers and transports that
// only need to query health should depend on this interface rather than the full
// Controllable.
type HealthReporter interface {
Status() HealthReport
Liveness() HealthReport
Readiness() HealthReport
GetServiceInfo(name string) (ServiceInfo, bool)
}
// HealthCheckReporter extends HealthReporter with check-specific queries.
type HealthCheckReporter interface {
HealthReporter
// GetCheckResult returns the latest result for a named health check.
GetCheckResult(name string) (CheckResult, bool)
}
// StateAccessor provides read access to controller state and context.
type StateAccessor interface {
GetState() State
SetState(state State)
GetContext() context.Context
GetLogger() *slog.Logger
}
// Configurable provides controller configuration setters.
//
// These setters mutate channel and logger fields that controller
// goroutines read after Start. They carry no internal synchronization
// and must only be called during construction — before Start — which is
// how the WithX ControllerOpt options apply them inside NewController.
// Calling any setter after Start races the running goroutines and is a
// programming error.
type Configurable interface {
SetErrorsChannel(errs chan error)
SetMessageChannel(control chan Message)
SetSignalsChannel(sigs chan os.Signal)
SetWaitGroup(wg *sync.WaitGroup)
SetShutdownTimeout(d time.Duration)
SetLogger(l *slog.Logger)
}
// ChannelProvider provides access to controller channels.
type ChannelProvider interface {
Messages() chan Message
Errors() chan error
Signals() chan os.Signal
}
// Controllable is the full controller interface, composed of all role-based interfaces.
// Prefer using the narrower interfaces (Runner, HealthReporter, Configurable, etc.) where possible.
type Controllable interface {
Runner
HealthReporter
StateAccessor
Configurable
ChannelProvider
}