zquit.go 1.63 KB
Newer Older
Vladimir Barsukov's avatar
Vladimir Barsukov committed
1
2
3
package zquit

import (
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
4
	"fmt"
Vladimir Barsukov's avatar
zgo    
Vladimir Barsukov committed
5
	"git.barsukov.pro/barsukov/zgo/zwg"
Vladimir Barsukov's avatar
Vladimir Barsukov committed
6
	"github.com/gin-gonic/gin"
Vladimir Barsukov's avatar
Vladimir Barsukov committed
7
	"log"
Vladimir Barsukov's avatar
Vladimir Barsukov committed
8
9
10
11
	"net/http"
	"os"
	"os/signal"
	"syscall"
Vladimir Barsukov's avatar
Vladimir Barsukov committed
12
	"time"
Vladimir Barsukov's avatar
Vladimir Barsukov committed
13
14
15
)

type ZQuit struct {
Vladimir Barsukov's avatar
Vladimir Barsukov committed
16
17
18
	Name        string
	PostWaitDur time.Duration

Vladimir Barsukov's avatar
Vladimir Barsukov committed
19
	isQuit bool
Vladimir Barsukov's avatar
zgo    
Vladimir Barsukov committed
20
	wg     *zwg.Zwg
Vladimir Barsukov's avatar
Vladimir Barsukov committed
21
22
}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
23
func New(name string, postWaitDur time.Duration) *ZQuit {
Vladimir Barsukov's avatar
zgo    
Vladimir Barsukov committed
24
	return &ZQuit{
Vladimir Barsukov's avatar
Vladimir Barsukov committed
25
26
27
28
29
30
31
32
33
		Name:        name,
		PostWaitDur: postWaitDur,
		wg:          zwg.New(),
	}
}

func Default(name ...string) *ZQuit {
	if len(name) == 0 {
		name = []string{"MAIN"}
Vladimir Barsukov's avatar
zgo    
Vladimir Barsukov committed
34
	}
Vladimir Barsukov's avatar
Vladimir Barsukov committed
35
36

	return New(name[0], time.Second)
Vladimir Barsukov's avatar
Vladimir Barsukov committed
37
38
39
}

func (q *ZQuit) Inc() {
Vladimir Barsukov's avatar
zgo    
Vladimir Barsukov committed
40
	q.wg.Inc()
Vladimir Barsukov's avatar
Vladimir Barsukov committed
41
42
43
44
45
46
47
48
49
50
51
}

func (q *ZQuit) Done() {
	q.wg.Done()
}

func (q *ZQuit) Wait() {
	q.wg.Wait()
}

func (q *ZQuit) IncDefer() func() {
Vladimir Barsukov's avatar
zgo    
Vladimir Barsukov committed
52
	return q.wg.IncDefer()
Vladimir Barsukov's avatar
Vladimir Barsukov committed
53
54
55
56
57
58
}

func (q *ZQuit) IsQuit() bool {
	return q.isQuit
}

Vladimir Barsukov's avatar
zgo    
Vladimir Barsukov committed
59
60
func (q *ZQuit) Val() int {
	return q.wg.Val()
Vladimir Barsukov's avatar
Vladimir Barsukov committed
61
62
63
64
65
66
67
}

func (q *ZQuit) WaitInterruptPrePost(pre func(), post func()) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	<-c

Vladimir Barsukov's avatar
Vladimir Barsukov committed
68
69
70
71
	if pre != nil {
		pre()
	}

Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
72
	q.Shutdown()
Vladimir Barsukov's avatar
Vladimir Barsukov committed
73
	q.Wait()
Vladimir Barsukov's avatar
Vladimir Barsukov committed
74
	time.Sleep(q.PostWaitDur)
Vladimir Barsukov's avatar
Vladimir Barsukov committed
75

Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
76
77
78
	if post != nil {
		post()
	}
Vladimir Barsukov's avatar
Vladimir Barsukov committed
79
80
81
}

func (q *ZQuit) WaitInterrupt() {
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
82
	q.WaitInterruptPrePost(nil, nil)
Vladimir Barsukov's avatar
Vladimir Barsukov committed
83
84
}

Vladimir Barsukov's avatar
zgo    
Vladimir Barsukov committed
85
func (q *ZQuit) Middleware(c *gin.Context) {
Vladimir Barsukov's avatar
Vladimir Barsukov committed
86
87
	if q.isQuit {
		c.Data(http.StatusServiceUnavailable, "text/plain", []byte("server shutdown"))
Vladimir Barsukov's avatar
Vladimir Barsukov committed
88
		c.Abort()
Vladimir Barsukov's avatar
lint    
Vladimir Barsukov committed
89

Vladimir Barsukov's avatar
Vladimir Barsukov committed
90
91
92
93
94
95
96
97
		return
	}

	cancel := q.IncDefer()
	defer cancel()

	c.Next()
}
Vladimir Barsukov's avatar
zgo    
Vladimir Barsukov committed
98

Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
99
100
101
102
func (q *ZQuit) GetStat() string {
	return fmt.Sprintf("%s: %v", q.Name, q.Val())
}
func (q *ZQuit) PrintStat(sec int) {
Vladimir Barsukov's avatar
Vladimir Barsukov committed
103
104
	go func() {
		for {
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
105
106
			time.Sleep(time.Second * time.Duration(sec))
			log.Printf("ZQUIT: %s", q.GetStat())
Vladimir Barsukov's avatar
Vladimir Barsukov committed
107
108
109
110
		}
	}()
}

Vladimir Barsukov's avatar
zgo    
Vladimir Barsukov committed
111
112
113
func (q *ZQuit) Shutdown() {
	q.isQuit = true
}