-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathstarter.go
132 lines (117 loc) · 2.76 KB
/
starter.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
package starter
import (
"fmt"
"os"
"os/signal"
"path"
"sync"
"syscall"
)
type command struct {
Name string
Run func() int
}
var commands = []*command{
cmdStart,
cmdStop,
cmdRestart,
}
var (
mutex sync.Mutex
osFile *os.File
closerFuncs []func() = make([]func(), 0)
doneChan chan bool = make(chan bool, 1)
waitChan chan bool = make(chan bool, 1)
signalChan chan os.Signal = make(chan os.Signal, 1)
appPath string = os.Args[0]
appName string = path.Base(appPath)
pidPath string = "./" + appName + ".pid"
)
// Инициализация
func init() {
if len(os.Args) > 1 {
name := os.Args[1]
for _, cmd := range commands {
if cmd.Name == name {
os.Exit(cmd.Run())
}
}
}
createPIDFileLockAndSet(pidPath, os.Getpid())
signalListen(signalChan, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP)
}
// Привязываем функцию завершения
func Bind(fn func()) {
mutex.Lock()
c := make([]func(), 0, len(closerFuncs)+1)
c = append(c, fn)
closerFuncs = append(c, closerFuncs...)
mutex.Unlock()
}
// Ждем пока не будет обработан выход
func Wait() {
<-waitChan
Println(appName + "stopping... ")
<-doneChan
Println(" stopped!\n")
os.Exit(0)
}
// Слушает сигналы завершения
func signalListen(signalChan chan os.Signal, siganls ...os.Signal) {
signal.Notify(signalChan, siganls...)
go func() {
<-signalChan
mutex.Lock()
defer mutex.Unlock()
waitChan <- true
for _, fn := range closerFuncs {
fn()
}
doneChan <- true
}()
}
// Создаем pid файл, блокируем и сохраняем в него новый pid
func createPIDFileLockAndSet(path string, pid int) {
pidFile := newPIDFile(path)
if err := pidFile.Lock(); err != nil {
Fatalln("PID not lock!")
}
if err := pidFile.Set(pid); err != nil {
Fatalln("PID not set!")
}
}
// Обертка над os.File для работы с PID файлом
type pidFile struct {
*os.File
}
func newPIDFile(path string) *pidFile {
var err error
osFile, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
Fatalln("PID file not open!")
}
return &pidFile{osFile}
}
func (file *pidFile) Set(pid int) error {
file.Truncate(0)
file.Seek(0, os.SEEK_SET)
_, err := fmt.Fprint(file, pid)
if err != nil {
return Errorln("PID not save!")
}
return nil
}
func (file *pidFile) Get() (int, error) {
var pid int = 0
_, err := fmt.Fscan(file, &pid)
if err != nil {
return 0, Errorln("PID not read!")
}
return pid, nil
}
func (file *pidFile) Lock() error {
return syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
}
func (file *pidFile) Unlock() error {
return syscall.Flock(int(file.Fd()), syscall.LOCK_UN)
}