mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-22 11:00:53 +08:00
Standardize exit codes and improve shutdown handling; update gitignore
This commit is contained in:
parent
2141626269
commit
b780f0f49b
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
||||||
_gitignore/
|
_gitignore/
|
||||||
|
*.log
|
||||||
|
Caddyfile
|
||||||
|
|
||||||
# artifacts from pprof tooling
|
# artifacts from pprof tooling
|
||||||
*.prof
|
*.prof
|
||||||
|
|
48
caddy.go
48
caddy.go
|
@ -150,21 +150,46 @@ func Run(newCfg *Config) error {
|
||||||
currentCfg = newCfg
|
currentCfg = newCfg
|
||||||
|
|
||||||
// Stop, Cleanup each old app
|
// Stop, Cleanup each old app
|
||||||
if oldCfg != nil {
|
unsyncedStop(oldCfg)
|
||||||
for name, a := range oldCfg.apps {
|
|
||||||
err := a.Stop()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("[ERROR] stop %s: %v", name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// clean up all old modules
|
|
||||||
oldCfg.cancelFunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop stops running the current configuration.
|
||||||
|
// It is the antithesis of Run(). This function
|
||||||
|
// will log any errors that occur during the
|
||||||
|
// stopping of individual apps and continue to
|
||||||
|
// stop the others.
|
||||||
|
func Stop() error {
|
||||||
|
currentCfgMu.Lock()
|
||||||
|
defer currentCfgMu.Unlock()
|
||||||
|
unsyncedStop(currentCfg)
|
||||||
|
currentCfg = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsyncedStop stops oldCfg from running, but if
|
||||||
|
// applicable, you need to acquire locks yourself.
|
||||||
|
// It is a no-op if oldCfg is nil. If any app
|
||||||
|
// returns an error when stopping, it is logged
|
||||||
|
// and the function continues with the next app.
|
||||||
|
func unsyncedStop(oldCfg *Config) {
|
||||||
|
if oldCfg == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop each app
|
||||||
|
for name, a := range oldCfg.apps {
|
||||||
|
err := a.Stop()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] stop %s: %v", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up all old modules
|
||||||
|
oldCfg.cancelFunc()
|
||||||
|
}
|
||||||
|
|
||||||
// Duration is a JSON-string-unmarshable duration type.
|
// Duration is a JSON-string-unmarshable duration type.
|
||||||
type Duration time.Duration
|
type Duration time.Duration
|
||||||
|
|
||||||
|
@ -199,6 +224,7 @@ func GoModule() *debug.Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
// goModule is the name of this Go module.
|
// goModule is the name of this Go module.
|
||||||
|
// TODO: we should be able to find this at runtime, see https://github.com/golang/go/issues/29228
|
||||||
const goModule = "github.com/caddyserver/caddy/v2"
|
const goModule = "github.com/caddyserver/caddy/v2"
|
||||||
|
|
||||||
// CtxKey is a value type for use with context.WithValue.
|
// CtxKey is a value type for use with context.WithValue.
|
||||||
|
|
|
@ -44,7 +44,8 @@ func cmdStart() (int, error) {
|
||||||
// it is ready to confirm that it has successfully started
|
// it is ready to confirm that it has successfully started
|
||||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("opening listener for success confirmation: %v", err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("opening listener for success confirmation: %v", err)
|
||||||
}
|
}
|
||||||
defer ln.Close()
|
defer ln.Close()
|
||||||
|
|
||||||
|
@ -63,7 +64,8 @@ func cmdStart() (int, error) {
|
||||||
}
|
}
|
||||||
stdinpipe, err := cmd.StdinPipe()
|
stdinpipe, err := cmd.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("creating stdin pipe: %v", err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("creating stdin pipe: %v", err)
|
||||||
}
|
}
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
|
@ -72,7 +74,7 @@ func cmdStart() (int, error) {
|
||||||
expect := make([]byte, 32)
|
expect := make([]byte, 32)
|
||||||
_, err = rand.Read(expect)
|
_, err = rand.Read(expect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("generating random confirmation bytes: %v", err)
|
return caddy.ExitCodeFailedStartup, fmt.Errorf("generating random confirmation bytes: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// begin writing the confirmation bytes to the child's
|
// begin writing the confirmation bytes to the child's
|
||||||
|
@ -87,7 +89,7 @@ func cmdStart() (int, error) {
|
||||||
// start the process
|
// start the process
|
||||||
err = cmd.Start()
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("starting caddy process: %v", err)
|
return caddy.ExitCodeFailedStartup, fmt.Errorf("starting caddy process: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// there are two ways we know we're done: either
|
// there are two ways we know we're done: either
|
||||||
|
@ -125,10 +127,11 @@ func cmdStart() (int, error) {
|
||||||
case <-success:
|
case <-success:
|
||||||
fmt.Println("Successfully started Caddy")
|
fmt.Println("Successfully started Caddy")
|
||||||
case err := <-exit:
|
case err := <-exit:
|
||||||
return 1, fmt.Errorf("caddy process exited with error: %v", err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("caddy process exited with error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdRun() (int, error) {
|
func cmdRun() (int, error) {
|
||||||
|
@ -144,7 +147,8 @@ func cmdRun() (int, error) {
|
||||||
var err error
|
var err error
|
||||||
config, err = ioutil.ReadFile(*runCmdConfigFlag)
|
config, err = ioutil.ReadFile(*runCmdConfigFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("reading config file: %v", err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("reading config file: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +160,8 @@ func cmdRun() (int, error) {
|
||||||
// start the admin endpoint along with any initial config
|
// start the admin endpoint along with any initial config
|
||||||
err := caddy.StartAdmin(config)
|
err := caddy.StartAdmin(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("starting caddy administration endpoint: %v", err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("starting caddy administration endpoint: %v", err)
|
||||||
}
|
}
|
||||||
defer caddy.StopAdmin()
|
defer caddy.StopAdmin()
|
||||||
|
|
||||||
|
@ -165,16 +170,19 @@ func cmdRun() (int, error) {
|
||||||
if *runCmdPingbackFlag != "" {
|
if *runCmdPingbackFlag != "" {
|
||||||
confirmationBytes, err := ioutil.ReadAll(os.Stdin)
|
confirmationBytes, err := ioutil.ReadAll(os.Stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("reading confirmation bytes from stdin: %v", err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("reading confirmation bytes from stdin: %v", err)
|
||||||
}
|
}
|
||||||
conn, err := net.Dial("tcp", *runCmdPingbackFlag)
|
conn, err := net.Dial("tcp", *runCmdPingbackFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("dialing confirmation address: %v", err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("dialing confirmation address: %v", err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
_, err = conn.Write(confirmationBytes)
|
_, err = conn.Write(confirmationBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("writing confirmation bytes to %s: %v", *runCmdPingbackFlag, err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("writing confirmation bytes to %s: %v", *runCmdPingbackFlag, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +192,7 @@ func cmdRun() (int, error) {
|
||||||
func cmdStop() (int, error) {
|
func cmdStop() (int, error) {
|
||||||
processList, err := ps.Processes()
|
processList, err := ps.Processes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("listing processes: %v", err)
|
return caddy.ExitCodeFailedStartup, fmt.Errorf("listing processes: %v", err)
|
||||||
}
|
}
|
||||||
thisProcName := filepath.Base(os.Args[0])
|
thisProcName := filepath.Base(os.Args[0])
|
||||||
var found bool
|
var found bool
|
||||||
|
@ -195,15 +203,15 @@ func cmdStop() (int, error) {
|
||||||
fmt.Printf("pid=%d\n", p.Pid())
|
fmt.Printf("pid=%d\n", p.Pid())
|
||||||
fmt.Printf("Graceful stop...")
|
fmt.Printf("Graceful stop...")
|
||||||
if err := gracefullyStopProcess(p.Pid()); err != nil {
|
if err := gracefullyStopProcess(p.Pid()); err != nil {
|
||||||
return 1, err
|
return caddy.ExitCodeFailedStartup, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
return 1, fmt.Errorf("Caddy is not running")
|
return caddy.ExitCodeFailedStartup, fmt.Errorf("Caddy is not running")
|
||||||
}
|
}
|
||||||
fmt.Println(" success")
|
fmt.Println(" success")
|
||||||
return 0, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdReload() (int, error) {
|
func cmdReload() (int, error) {
|
||||||
|
@ -214,13 +222,15 @@ func cmdReload() (int, error) {
|
||||||
|
|
||||||
// a configuration is required
|
// a configuration is required
|
||||||
if *reloadCmdConfigFlag == "" {
|
if *reloadCmdConfigFlag == "" {
|
||||||
return 1, fmt.Errorf("no configuration to load (use --config)")
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("no configuration to load (use --config)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the configuration file
|
// load the configuration file
|
||||||
config, err := ioutil.ReadFile(*reloadCmdConfigFlag)
|
config, err := ioutil.ReadFile(*reloadCmdConfigFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("reading config file: %v", err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("reading config file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the address of the admin listener and craft endpoint URL
|
// get the address of the admin listener and craft endpoint URL
|
||||||
|
@ -231,7 +241,8 @@ func cmdReload() (int, error) {
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(config, &tmpStruct)
|
err = json.Unmarshal(config, &tmpStruct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("unmarshaling admin listener address from config: %v", err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("unmarshaling admin listener address from config: %v", err)
|
||||||
}
|
}
|
||||||
adminAddr = tmpStruct.Admin.Listen
|
adminAddr = tmpStruct.Admin.Listen
|
||||||
}
|
}
|
||||||
|
@ -243,7 +254,8 @@ func cmdReload() (int, error) {
|
||||||
// send the configuration to the instance
|
// send the configuration to the instance
|
||||||
resp, err := http.Post(adminEndpoint, "application/json", bytes.NewReader(config))
|
resp, err := http.Post(adminEndpoint, "application/json", bytes.NewReader(config))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("sending configuration to instance: %v", err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("sending configuration to instance: %v", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
@ -251,12 +263,14 @@ func cmdReload() (int, error) {
|
||||||
if resp.StatusCode >= 400 {
|
if resp.StatusCode >= 400 {
|
||||||
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1024*10))
|
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1024*10))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, fmt.Errorf("HTTP %d: reading error message: %v", resp.StatusCode, err)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("HTTP %d: reading error message: %v", resp.StatusCode, err)
|
||||||
}
|
}
|
||||||
return 1, fmt.Errorf("caddy responded with error: HTTP %d: %s", resp.StatusCode, respBody)
|
return caddy.ExitCodeFailedStartup,
|
||||||
|
fmt.Errorf("caddy responded with error: HTTP %d: %s", resp.StatusCode, respBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdVersion() (int, error) {
|
func cmdVersion() (int, error) {
|
||||||
|
@ -267,19 +281,19 @@ func cmdVersion() (int, error) {
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(goModule.Version)
|
fmt.Println(goModule.Version)
|
||||||
}
|
}
|
||||||
return 0, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdListModules() (int, error) {
|
func cmdListModules() (int, error) {
|
||||||
for _, m := range caddy.Modules() {
|
for _, m := range caddy.Modules() {
|
||||||
fmt.Println(m)
|
fmt.Println(m)
|
||||||
}
|
}
|
||||||
return 0, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdEnviron() (int, error) {
|
func cmdEnviron() (int, error) {
|
||||||
for _, v := range os.Environ() {
|
for _, v := range os.Environ() {
|
||||||
fmt.Println(v)
|
fmt.Println(v)
|
||||||
}
|
}
|
||||||
return 0, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,15 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Main executes the main function of the caddy command.
|
// Main implements the main function of the caddy command.
|
||||||
|
// Call this if Caddy is to be the main() if your program.
|
||||||
func Main() {
|
func Main() {
|
||||||
|
caddy.TrapSignals()
|
||||||
|
|
||||||
if len(os.Args) <= 1 {
|
if len(os.Args) <= 1 {
|
||||||
fmt.Println(usageString())
|
fmt.Println(usageString())
|
||||||
return
|
return
|
||||||
|
@ -35,7 +40,7 @@ func Main() {
|
||||||
subcommand, ok := commands[os.Args[1]]
|
subcommand, ok := commands[os.Args[1]]
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Printf("%q is not a valid command\n", os.Args[1])
|
fmt.Printf("%q is not a valid command\n", os.Args[1])
|
||||||
os.Exit(2)
|
os.Exit(caddy.ExitCodeFailedStartup)
|
||||||
}
|
}
|
||||||
|
|
||||||
if exitCode, err := subcommand(); err != nil {
|
if exitCode, err := subcommand(); err != nil {
|
||||||
|
|
82
sigtrap.go
Normal file
82
sigtrap.go
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package caddy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
|
"github.com/mholt/certmagic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TrapSignals create signal/interrupt handlers as best it can for the
|
||||||
|
// current OS. This is a rather invasive function to call in a Go program
|
||||||
|
// that captures signals already, so in that case it would be better to
|
||||||
|
// implement these handlers yourself.
|
||||||
|
func TrapSignals() {
|
||||||
|
trapSignalsCrossPlatform()
|
||||||
|
trapSignalsPosix()
|
||||||
|
}
|
||||||
|
|
||||||
|
// trapSignalsCrossPlatform captures SIGINT or interrupt (depending
|
||||||
|
// on the OS), which initiates a graceful shutdown. A second SIGINT
|
||||||
|
// or interrupt will forcefully exit the process immediately.
|
||||||
|
func trapSignalsCrossPlatform() {
|
||||||
|
go func() {
|
||||||
|
shutdown := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(shutdown, os.Interrupt)
|
||||||
|
|
||||||
|
for i := 0; true; i++ {
|
||||||
|
<-shutdown
|
||||||
|
|
||||||
|
if i > 0 {
|
||||||
|
log.Println("[INFO] SIGINT: Force quit")
|
||||||
|
os.Exit(ExitCodeForceQuit)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("[INFO] SIGINT: Shutting down")
|
||||||
|
go gracefulStop("SIGINT")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// gracefulStop exits the process as gracefully as possible.
|
||||||
|
func gracefulStop(sigName string) {
|
||||||
|
exitCode := ExitCodeSuccess
|
||||||
|
|
||||||
|
// first stop all the apps
|
||||||
|
err := Stop()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] %s stop: %v", sigName, err)
|
||||||
|
exitCode = ExitCodeFailedQuit
|
||||||
|
}
|
||||||
|
|
||||||
|
// always, always, always try to clean up locks
|
||||||
|
certmagic.CleanUpOwnLocks()
|
||||||
|
|
||||||
|
log.Printf("[INFO] %s: Shutdown done", sigName)
|
||||||
|
os.Exit(exitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit codes. Generally, you will want to avoid
|
||||||
|
// automatically restarting the process if the
|
||||||
|
// exit code is 1.
|
||||||
|
const (
|
||||||
|
ExitCodeSuccess = iota
|
||||||
|
ExitCodeFailedStartup
|
||||||
|
ExitCodeForceQuit
|
||||||
|
ExitCodeFailedQuit
|
||||||
|
)
|
19
sigtrap_nonposix.go
Normal file
19
sigtrap_nonposix.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build windows plan9 nacl js
|
||||||
|
|
||||||
|
package caddy
|
||||||
|
|
||||||
|
func trapSignalsPosix() {}
|
57
sigtrap_posix.go
Normal file
57
sigtrap_posix.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build !windows,!plan9,!nacl,!js
|
||||||
|
|
||||||
|
package caddy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/mholt/certmagic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// trapSignalsPosix captures POSIX-only signals.
|
||||||
|
func trapSignalsPosix() {
|
||||||
|
go func() {
|
||||||
|
sigchan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigchan, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2)
|
||||||
|
|
||||||
|
for sig := range sigchan {
|
||||||
|
switch sig {
|
||||||
|
case syscall.SIGQUIT:
|
||||||
|
log.Println("[INFO] SIGQUIT: Quitting process immediately")
|
||||||
|
certmagic.CleanUpOwnLocks() // try to clean up locks anyway, it's important
|
||||||
|
os.Exit(ExitCodeForceQuit)
|
||||||
|
|
||||||
|
case syscall.SIGTERM:
|
||||||
|
log.Println("[INFO] SIGTERM: Shutting down apps then terminating")
|
||||||
|
gracefulStop("SIGTERM")
|
||||||
|
|
||||||
|
case syscall.SIGUSR1:
|
||||||
|
log.Println("[INFO] SIGUSR1: Not implemented")
|
||||||
|
|
||||||
|
case syscall.SIGUSR2:
|
||||||
|
log.Println("[INFO] SIGUSR2: Not implemented")
|
||||||
|
|
||||||
|
case syscall.SIGHUP:
|
||||||
|
// ignore; this signal is sometimes sent outside of the user's control
|
||||||
|
log.Println("[INFO] SIGHUP: Not implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user