forked from flashmob/go-guerrilla
-
Notifications
You must be signed in to change notification settings - Fork 0
/
serve.go
149 lines (131 loc) · 4.04 KB
/
serve.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
147
148
149
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/flashmob/go-guerrilla"
"github.com/flashmob/go-guerrilla/log"
// enable the Redis redigo driver
_ "github.com/flashmob/go-guerrilla/backends/storage/redigo"
// Choose iconv or mail/encoding package which uses golang.org/x/net/html/charset
//_ "github.com/flashmob/go-guerrilla/mail/iconv"
_ "github.com/flashmob/go-guerrilla/mail/encoding"
"github.com/spf13/cobra"
_ "github.com/go-sql-driver/mysql"
)
const (
defaultPidFile = "/var/run/go-guerrilla.pid"
)
var (
configPath string
pidFile string
serveCmd = &cobra.Command{
Use: "serve",
Short: "start the daemon and start all available servers",
Run: serve,
}
signalChannel = make(chan os.Signal, 1) // for trapping SIGHUP and friends
mainlog log.Logger
d guerrilla.Daemon
)
func init() {
// log to stderr on startup
var err error
mainlog, err = log.GetLogger(log.OutputStderr.String(), log.InfoLevel.String())
if err != nil && mainlog != nil {
mainlog.WithError(err).Errorf("Failed creating a logger to %s", log.OutputStderr)
}
cfgFile := "goguerrilla.conf" // deprecated default name
if _, err := os.Stat(cfgFile); err != nil {
cfgFile = "goguerrilla.conf.json" // use the new name
}
serveCmd.PersistentFlags().StringVarP(&configPath, "config", "c",
cfgFile, "Path to the configuration file")
// intentionally didn't specify default pidFile; value from config is used if flag is empty
serveCmd.PersistentFlags().StringVarP(&pidFile, "pidFile", "p",
"", "Path to the pid file")
rootCmd.AddCommand(serveCmd)
}
func sigHandler() {
signal.Notify(signalChannel,
syscall.SIGHUP,
syscall.SIGTERM,
syscall.SIGQUIT,
syscall.SIGINT,
syscall.SIGKILL,
syscall.SIGUSR1,
os.Kill,
)
for sig := range signalChannel {
if sig == syscall.SIGHUP {
if ac, err := readConfig(configPath, pidFile); err == nil {
_ = d.ReloadConfig(*ac)
} else {
mainlog.WithError(err).Error("Could not reload config")
}
} else if sig == syscall.SIGUSR1 {
if err := d.ReopenLogs(); err != nil {
mainlog.WithError(err).Error("reopening logs failed")
}
} else if sig == syscall.SIGTERM || sig == syscall.SIGQUIT || sig == syscall.SIGINT || sig == os.Kill {
mainlog.Infof("Shutdown signal caught")
go func() {
select {
// exit if graceful shutdown not finished in 60 sec.
case <-time.After(time.Second * 60):
mainlog.Error("graceful shutdown timed out")
os.Exit(1)
}
}()
d.Shutdown()
mainlog.Infof("Shutdown completed, exiting.")
return
} else {
mainlog.Infof("Shutdown, unknown signal caught")
return
}
}
}
func serve(cmd *cobra.Command, args []string) {
logVersion()
d = guerrilla.Daemon{Logger: mainlog}
c, err := readConfig(configPath, pidFile)
if err != nil {
mainlog.WithError(err).Fatal("Error while reading config")
}
_ = d.SetConfig(*c)
// Check that max clients is not greater than system open file limit.
if ok, maxClients, fileLimit := guerrilla.CheckFileLimit(c); !ok {
mainlog.Fatalf("Combined max clients for all servers (%d) is greater than open file limit (%d). "+
"Please increase your open file limit or decrease max clients.", maxClients, fileLimit)
}
err = d.Start()
if err != nil {
mainlog.WithError(err).Error("Error(s) when creating new server(s)")
os.Exit(1)
}
sigHandler()
}
// ReadConfig is called at startup, or when a SIG_HUP is caught
func readConfig(path string, pidFile string) (*guerrilla.AppConfig, error) {
// Load in the config.
// Note here is the only place we can make an exception to the
// "treat config values as immutable". For example, here the
// command line flags can override config values
appConfig, err := d.LoadConfig(path)
if err != nil {
return &appConfig, fmt.Errorf("could not read config file: %s", err.Error())
}
// override config pidFile with with flag from the command line
if len(pidFile) > 0 {
appConfig.PidFile = pidFile
} else if len(appConfig.PidFile) == 0 {
appConfig.PidFile = defaultPidFile
}
if verbose {
appConfig.LogLevel = "debug"
}
return &appConfig, nil
}