-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgovservice.go
153 lines (138 loc) · 3.9 KB
/
govservice.go
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
package governor
import (
"context"
"fmt"
"io/fs"
"sync/atomic"
"xorkevin.dev/governor/util/uid"
"xorkevin.dev/kerrors"
"xorkevin.dev/klog"
)
type (
// Service is an interface for governor services
//
// A governor service may be in one of 4 stages in its lifecycle.
//
// 1. Register: register the service config
// 2. Init: read configuration and make service functional
// 3. Start: start the service
// 4. Stop: stop the service
//
// A setup task runs through the following lifecycle methods
//
// 1. Register: register the service config
// 2. Init: read configuration and make service functional
// 3. Setup: sets up the service
// 4. Stop: stop the service
//
// Furthermore, a service may be polled for its health via Health.
Service interface {
Register(r ConfigRegistrar)
Init(ctx context.Context, r ConfigReader, kit ServiceKit) error
Start(ctx context.Context) error
Stop(ctx context.Context)
Setup(ctx context.Context, req ReqSetup) error
Health(ctx context.Context) error
}
ServiceKit struct {
Logger klog.Logger
Router Router
Tracer Tracer
Fsys fs.FS
}
serviceOpt struct {
name string
url string
}
serviceDef struct {
opt serviceOpt
r Service
}
)
// Register adds the service to the governor Server and runs service.Register
func (s *Server) Register(name string, url string, r Service) {
s.services = append(s.services, serviceDef{
opt: serviceOpt{
name: name,
url: url,
},
r: r,
})
r.Register(s.settings.registrar(name))
}
func (s *Server) setupServices(ctx context.Context, rsetup ReqSetup) error {
s.log.Info(ctx, "Setup all services begin")
for _, i := range s.services {
if err := i.r.Setup(ctx, rsetup); err != nil {
err := kerrors.WithMsg(err, "Setup service failed")
s.log.Err(ctx, err, klog.AString("service", i.opt.name))
return err
}
s.log.Info(ctx, "Setup service success", klog.AString("service", i.opt.name))
}
s.log.Info(ctx, "Setup all services complete")
return nil
}
func (s *Server) checkHealthServices(ctx context.Context) []error {
var k []error
for _, i := range s.services {
if err := i.r.Health(ctx); err != nil {
k = append(k, kerrors.WithMsg(err, fmt.Sprintf("Failed healthcheck for service %s", i.opt.name)))
}
}
return k
}
func (s *Server) initServices(ctx context.Context) error {
s.log.Info(ctx, "Init all services begin")
for _, i := range s.services {
l := s.log.Logger.Sublogger(i.opt.name, klog.AString("gov.service", i.opt.name))
if err := i.r.Init(ctx, s.settings.reader(i.opt), ServiceKit{
Logger: l,
Router: s.router(s.settings.config.BasePath+i.opt.url, l),
Tracer: s.tracer,
Fsys: s.settings.fsys,
}); err != nil {
err := kerrors.WithMsg(err, "Init service failed")
s.log.Err(ctx, err, klog.AString("service", i.opt.name))
return err
}
s.log.Info(ctx, "Init service success", klog.AString("service", i.opt.name))
}
s.log.Info(ctx, "Init all services complete")
return nil
}
func (s *Server) startServices(ctx context.Context) error {
s.log.Info(ctx, "Start all services begin")
for _, i := range s.services {
if err := i.r.Start(ctx); err != nil {
err := kerrors.WithMsg(err, "Start service failed")
s.log.Err(ctx, err, klog.AString("service", i.opt.name))
return err
}
s.log.Info(ctx, "Start service success", klog.AString("service", i.opt.name))
}
s.log.Info(ctx, "Start all services complete")
return nil
}
func (s *Server) stopServices(ctx context.Context) {
s.log.Info(ctx, "Stop all services begin")
sl := len(s.services)
for n := range s.services {
i := s.services[sl-n-1]
i.r.Stop(ctx)
s.log.Info(ctx, "Stop service", klog.AString("service", i.opt.name))
}
s.log.Info(ctx, "Stop all services complete")
}
type (
Tracer interface {
LReqID() string
}
tracer struct {
instance string
reqcount atomic.Uint32
}
)
func (t *tracer) LReqID() string {
return uid.NewSnowflake(t.reqcount.Add(1)).Base64() + t.instance
}