-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.go
143 lines (126 loc) · 3.28 KB
/
app.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
package dove
import (
"context"
"errors"
"os"
"os/signal"
"sync"
"syscall"
"time"
"github.com/camry/g/glog"
"github.com/google/uuid"
"golang.org/x/sync/errgroup"
)
// AppInfo 应用程序上下文值接口。
type AppInfo interface {
ID() string
Name() string
Version() string
}
// App 应用程序组件生命周期管理器。
type App struct {
opt option
ctx context.Context
cancel context.CancelFunc
}
// New 创建应用生命周期管理器。
func New(opts ...Option) *App {
o := option{
ctx: context.Background(),
sigs: []os.Signal{syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT},
stopTimeout: 10 * time.Second,
}
if id, err := uuid.NewUUID(); err == nil {
o.id = id.String()
}
for _, opt := range opts {
opt(&o)
}
if o.logger != nil {
glog.SetLogger(o.logger)
}
ctx, cancel := context.WithCancel(o.ctx)
return &App{
ctx: ctx,
cancel: cancel,
opt: o,
}
}
// ID 返回服务实例ID。
func (a *App) ID() string { return a.opt.id }
// Name 返回服务名称。
func (a *App) Name() string { return a.opt.name }
// Version 返回服务版本号。
func (a *App) Version() string { return a.opt.version }
// Run 执行应用程序生命周期中注册的所有服务。
func (a *App) Run() (err error) {
sCtx := NewContext(a.ctx, a)
eg, ctx := errgroup.WithContext(sCtx)
wg := sync.WaitGroup{}
for _, fn := range a.opt.beforeStart {
if err = fn(sCtx); err != nil {
return err
}
}
// 启动注册的服务器。
for _, srv := range a.opt.servers {
server := srv
eg.Go(func() error {
<-ctx.Done() // 等待停止信号
stopCtx, cancel := context.WithTimeout(NewContext(a.opt.ctx, a), a.opt.stopTimeout)
defer cancel()
return server.Stop(stopCtx)
})
wg.Add(1)
eg.Go(func() error {
wg.Done()
return server.Start(NewContext(a.opt.ctx, a))
})
}
wg.Wait()
for _, fn := range a.opt.afterStart {
if err = fn(sCtx); err != nil {
return err
}
}
c := make(chan os.Signal, 1)
signal.Notify(c, a.opt.sigs...)
// 停止应用程序。
eg.Go(func() error {
select {
case <-ctx.Done():
return nil
case <-c:
return a.Stop()
}
})
if err = eg.Wait(); err != nil && !errors.Is(err, context.Canceled) {
return err
}
err = nil
for _, fn := range a.opt.afterStop {
err = fn(sCtx)
}
return err
}
// Stop 优雅的停止应用程序。
func (a *App) Stop() (err error) {
sCtx := NewContext(a.ctx, a)
for _, fn := range a.opt.beforeStop {
err = fn(sCtx)
}
if a.cancel != nil {
a.cancel()
}
return err
}
type appKey struct{}
// NewContext 返回一个带有值的新上下文。
func NewContext(ctx context.Context, a AppInfo) context.Context {
return context.WithValue(ctx, appKey{}, a)
}
// FromContext 返回存储在 ctx 中的传输值(如果有)。
func FromContext(ctx context.Context) (a AppInfo, ok bool) {
a, ok = ctx.Value(appKey{}).(AppInfo)
return
}