Matthew Holt
6 years ago
7 changed files with 242 additions and 37 deletions
@ -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 |
||||
|
) |
@ -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() {} |
@ -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