- Remove CAS, as it no longer works for us - Remove other checks - Implement 15 minute greet timeout check - Fix chat logos - Ditch thirdparty logger, use stdlib log facility wrapper for logging
91 lines
2.7 KiB
Go
91 lines
2.7 KiB
Go
package moon
|
|
|
|
import (
|
|
"os"
|
|
"os/signal"
|
|
|
|
"bunny-bot/internal/mylog"
|
|
)
|
|
|
|
// InstallSignalHandler registers every signal the bot cares about and starts the
|
|
// handler goroutine. The signal sets differ per platform, so the knowledge lives
|
|
// behind terminationSignals and reopenSignals rather than leaking into main.
|
|
func InstallSignalHandler() {
|
|
signal.Notify(SigChan, terminationSignals()...)
|
|
signal.Notify(SigChan, reopenSignals()...)
|
|
|
|
go SigHandler()
|
|
}
|
|
|
|
// SigHandler handles signals until one asks the process to quit.
|
|
//
|
|
// It stops the program; it does not end it. os.Exit here would skip main's
|
|
// deferred cleanup, and would report success whether or not the teardown actually
|
|
// worked — a service manager told "clean shutdown" over a log nobody can write to
|
|
// again is worse than one told to restart us. So the handler runs the teardown and
|
|
// returns; main decides the exit status from its own call to Shutdown.
|
|
func SigHandler() {
|
|
for s := range SigChan {
|
|
if !handleSignal(s) {
|
|
continue
|
|
}
|
|
|
|
if err := shutdown(); err != nil {
|
|
// The main log is already closed by now, so this is the last line we
|
|
// get to write; main still exits non-zero over the same failure.
|
|
mylog.Errorf("Shutdown did not complete cleanly: %s", err)
|
|
}
|
|
|
|
return
|
|
}
|
|
}
|
|
|
|
// handleSignal applies one signal and reports whether it means "shut down".
|
|
//
|
|
// Reopen signals re-open the log file, which is what a log rotation tool needs
|
|
// after it has moved the file aside. Neither of them is expected on Windows,
|
|
// and an unrecognised signal is ignored rather than treated as a quit.
|
|
func handleSignal(s os.Signal) bool {
|
|
if containsSignal(reopenSignals(), s) {
|
|
mylog.Infof("Got %s, re-opening the log file", s)
|
|
|
|
if err := mylog.ReOpen(); err != nil {
|
|
// Reopening can legitimately fail — the destination may not be a
|
|
// file at all, or the logger may already be closed. Logging is
|
|
// best-effort here because the log is exactly what just broke.
|
|
mylog.Errorf("Unable to re-open the log file on %s: %s", s, err)
|
|
} else {
|
|
mylog.Info("Log file re-opened")
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
if !containsSignal(terminationSignals(), s) {
|
|
// Make new iteration since we 've got signal we not interested in.
|
|
return false
|
|
}
|
|
|
|
// The status has to be recorded here, before the teardown runs: main reads
|
|
// it after Shutdown returns, and neither of them can reconstruct which
|
|
// signal triggered all of this by then.
|
|
recordExitCode(s)
|
|
|
|
mylog.Infof("Got %s, quitting", s)
|
|
|
|
return true
|
|
}
|
|
|
|
// containsSignal reports whether sig is in the set.
|
|
func containsSignal(set []os.Signal, sig os.Signal) bool {
|
|
for _, s := range set {
|
|
if s == sig {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|