Graceful shutdown
直接翻譯是 「優雅的關機」
這種做法是在收到程式終止
的指令時,先處理好執行中的動作才結束程式。
使用這個機制可以正確的關閉連線,完成處理到一半的任務。能夠保障工作跟資料的完整性,避免突然的中止程式造成一些奇怪的問題。
實作方法有很多種,這次要試試看使用 select + channel
來達到 graceful shutdown
自己寫的 goroutine。
struct#
在 struct
宣告一個 stopChan
用來傳送中止訊息
1
2
3
| type grace struct {
stopChan chan struct{}
}
|
用 select
語法,一個 case
定時執行任務,一個 case
等待 stopChan
傳值
接到 stopChan
傳來資料後,就會離開 for loop,結束這個 function
1
2
3
4
5
6
7
8
9
10
11
| func (g *grace) Run() {
for {
select {
case <-time.After(time.Second):
fmt.Println(">", time.Now())
case <-g.stopChan:
fmt.Println("stop run method")
return
}
}
}
|
再加上一個 Stop method 發送資料到 stopChan
1
2
3
| func (g *grace) Stop() {
g.stopChan <- struct{}{}
}
|
main function#
使用 go g.Run()
建立一個 goroutine 在背景運行
termChan
等待 interrupt 訊號,收到訊號後執行 Stop()
停止 goroutine 才結束程式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| func main() {
fmt.Println("start...")
termChan := make(chan os.Signal)
signal.Notify(termChan, syscall.SIGTERM, syscall.SIGINT)
g := NewGrace()
go g.Run()
// stop goroutine when catch interrupt signal
<-termChan
log.Print("SIGTERM received. close goroutine\n")
g.Stop()
fmt.Println("end...")
}
|
完整程式碼#
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
| package main
import (
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
fmt.Println("start...")
termChan := make(chan os.Signal)
signal.Notify(termChan, syscall.SIGTERM, syscall.SIGINT)
g := NewGrace()
go g.Run()
// stop goroutine when catch interrupt signal
<-termChan
log.Print("SIGTERM received. close goroutine\n")
g.Stop()
fmt.Println("end...")
}
type grace struct {
stopChan chan struct{}
}
func NewGrace() *grace {
return &grace{
stopChan: make(chan struct{}),
}
}
// Run service with timer
func (g *grace) Run() {
for {
select {
case <-time.After(time.Second):
fmt.Println(">", time.Now())
case <-g.stopChan:
fmt.Println("stop run method")
return
}
}
}
// Stop running service
func (g *grace) Stop() {
g.stopChan <- struct{}{}
}
|
Reference#