-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgin.go
146 lines (135 loc) · 3.43 KB
/
gin.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
package web
import (
"context"
"errors"
"fmt"
"net/http"
"os"
"os/signal"
"runtime"
"sync"
"syscall"
"time"
"github.com/gin-gonic/gin"
"github.com/go-pay/limiter"
"github.com/go-pay/web/middleware"
"github.com/go-pay/xlog"
"github.com/go-pay/xtime"
)
type GinEngine struct {
server *http.Server
Gin *gin.Engine
timeout time.Duration
wg sync.WaitGroup
addrPort string
hookMaps map[hookType][]func(c context.Context)
}
func InitGin(c *Config) *GinEngine {
if c == nil {
c = &Config{Addr: ":2233"}
}
g := gin.New()
engine := &GinEngine{Gin: g, wg: sync.WaitGroup{}, addrPort: c.Addr, hookMaps: make(map[hookType][]func(c context.Context))}
if c.ReadTimeout == 0 {
c.ReadTimeout = xtime.Duration(60 * time.Second)
}
if c.WriteTimeout == 0 {
c.WriteTimeout = xtime.Duration(60 * time.Second)
}
engine.timeout = time.Duration(c.ReadTimeout)
engine.server = &http.Server{
Addr: engine.addrPort,
Handler: g.Handler(),
ReadTimeout: time.Duration(c.ReadTimeout),
WriteTimeout: time.Duration(c.WriteTimeout),
}
g.Use(middleware.Logger(), middleware.Recovery())
if c.Limiter != nil && c.Limiter.Rate != 0 {
g.Use(middleware.Limiter("", limiter.NewLimiter(c.Limiter)))
}
if !c.Debug {
gin.SetMode(gin.ReleaseMode)
}
return engine
}
// 添加 GinServer 服务关闭时的钩子函数
func (g *GinEngine) AddShutdownHook(hooks ...HookFunc) *GinEngine {
for _, fn := range hooks {
if fn != nil {
g.hookMaps[_HookShutdown] = append(g.hookMaps[_HookShutdown], fn)
}
}
return g
}
// 添加 GinServer 进程退出时钩子函数
func (g *GinEngine) AddExitHook(hooks ...HookFunc) *GinEngine {
for _, fn := range hooks {
if fn != nil {
g.hookMaps[_HookExit] = append(g.hookMaps[_HookExit], fn)
}
}
return g
}
func (g *GinEngine) Start() {
// monitoring signal
go g.goNotifySignal()
// start gin http server
xlog.Warnf("Listening and serving HTTP on %s", g.addrPort)
if err := g.server.ListenAndServe(); err != nil {
if !errors.Is(err, http.ErrServerClosed) {
panic(fmt.Sprintf("server.ListenAndServe(), error(%+v).", err))
}
xlog.Warn("http: Server closed")
}
xlog.Warn("wait for process working finished")
// wait for process finished
g.wg.Wait()
xlog.Warn("process exit")
}
// 监听信号
func (g *GinEngine) goNotifySignal() {
g.wg.Add(1)
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
for {
si := <-ch
switch si {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
xlog.Warnf("get a signal %s, stop the process", si.String())
// close gin http server
g.Close()
ctx, cancelFunc := context.WithTimeout(context.Background(), g.timeout)
// call before close hooks
go func() {
if a := recover(); a != nil {
xlog.Errorf("panic: %v", a)
}
for _, fn := range g.hookMaps[_HookShutdown] {
fn(ctx)
}
}()
// wait for program finish processing
xlog.Warnf("waiting for the process to finish %v", g.timeout)
time.Sleep(g.timeout)
cancelFunc()
// call after close hooks
for _, fn := range g.hookMaps[_HookExit] {
fn(context.Background())
}
// notify process exit
g.wg.Done()
runtime.Gosched()
return
case syscall.SIGHUP:
default:
return
}
}
}
func (g *GinEngine) Close() {
if g.server != nil {
// disable keep-alives on existing connections
g.server.SetKeepAlivesEnabled(false)
_ = g.server.Shutdown(context.Background())
}
}