/
daemon.go
110 lines (95 loc) · 2.84 KB
/
daemon.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
package daemon
import (
"fmt"
"log"
"os"
"os/signal"
"syscall"
"github.com/takama/daemon"
)
var logf = log.Printf
// 设置日志记录函数
func SetLogFunc(f func(format string, a ...interface{})) {
logf = f
}
// service has embedded daemon
type service struct {
daemon.Daemon
serviceName string
serviceDescription string
dependencies []string
}
// Manage by daemon commands or run the daemon
func (s *service) Manage(onStart func(), onShutdown func() error) (string, error) {
usage := fmt.Sprintf("Usage: %s install | remove | start | stop | status", s.serviceName)
// if received any kind of command, do it
if len(os.Args) > 1 {
command := os.Args[1]
switch command {
case "install":
return s.Install()
case "remove":
return s.Remove()
case "start":
return s.Start()
case "stop":
return s.Stop()
case "status":
return s.Status()
default:
return usage, nil
}
}
// Do something, call your goroutines, etc
// Set up channel on which to send signal notifications.
// We must use a buffered channel or risk missing the signal
// if we're not ready to receive when the signal is sent.
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)
// 启动服务
onStart()
// loop work cycle with accept connections or interrupt
// by system signal
for {
select {
case killSignal := <-interrupt:
logf("Got signal: %v", killSignal)
logf("Stopping server...")
if err := onShutdown(); err != nil {
return "Daemon shutdown server failed", err
}
if killSignal == os.Interrupt {
return "Daemon was interrupted by system signal", nil
}
return "Daemon was killed", nil
}
}
}
type Kind daemon.Kind
const (
UserAgent = daemon.UserAgent
GlobalAgent = daemon.GlobalAgent
GlobalDaemon = daemon.GlobalDaemon
SystemDaemon = daemon.SystemDaemon
)
// 启动服务,一般在 main() 函数中执行
// serviceName 服务名称
// serviceDescription 服务介绍
// kind 服务类型,darwin 不能使用 SystemDaemon,freebsd、linux、windows 只能使用 SystemDaemon
// dependencies 服务依赖项,一般为 nil
// onStart 启动服务函数,如果函数内有阻塞的代码(比如监听服务器),需要自己创建 goroutine
// onShutdown 关闭服务函数,用于接收到关闭信号后执行相应的清理,当函数结束时进程将退出
func Run(serviceName string, serviceDescription string, kind daemon.Kind, dependencies []string, onStart func(), onShutdown func() error) {
srv, err := daemon.New(serviceName, serviceDescription, kind, dependencies...)
if err != nil {
logf("Error: %s", err)
os.Exit(1)
}
service := &service{srv, serviceName, serviceDescription, dependencies}
status, err := service.Manage(onStart, onShutdown)
if err != nil {
logf("Status %s: %s", status, err)
os.Exit(1)
}
logf(status)
}