fix bugs with restarts/interrupts

The password reset daemon wasn't being closed on restarts, so an extra
pwr would be sent w/ every restart. Restarts & Interrupts (Ctrl-C)
rarely worked, as there were multiple listeners to the "RESTART"
channel, and I didn't know the message was consumed by whoever got it
first, meaning if the main thread didn't get it first, the app wouldn't
quit. Listeners are now registered, and the restart message is
re-broadcasted until everyone's got it.

Fixes #264
pull/270/head
Harvey Tindall 1 year ago
parent f88f71d933
commit ad40d7d8a9
No known key found for this signature in database
GPG Key ID: BBC65952848FB1A2

@ -359,6 +359,8 @@ func (app *appContext) ModifyConfig(gc *gin.Context) {
} else { } else {
RESTART <- true RESTART <- true
} }
// Safety Sleep (Ensure shutdown tasks get done)
time.Sleep(time.Second)
} }
app.loadConfig() app.loadConfig()
// Reinitialize password validator on config change, as opposed to every applicable request like in python. // Reinitialize password validator on config change, as opposed to every applicable request like in python.
@ -527,5 +529,7 @@ func (app *appContext) Restart() error {
} else { } else {
RESTART <- true RESTART <- true
} }
// Safety Sleep (Ensure shutdown tasks get done)
time.Sleep(time.Second)
return nil return nil
} }

@ -120,7 +120,7 @@ func (d *DiscordDaemon) run() {
defer d.deregisterCommands() defer d.deregisterCommands()
defer d.bot.Close() defer d.bot.Close()
d.registerCommands() go d.registerCommands()
<-d.ShutdownChannel <-d.ShutdownChannel
d.ShutdownChannel <- "Down" d.ShutdownChannel <- "Down"

@ -17,6 +17,7 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
"syscall"
"time" "time"
"github.com/fatih/color" "github.com/fatih/color"
@ -43,6 +44,8 @@ var (
SWAGGER *bool SWAGGER *bool
QUIT = false QUIT = false
RUNNING = false RUNNING = false
// Used to know how many times to re-broadcast restart signal.
RESTARTLISTENERCOUNT = 0
warning = color.New(color.FgYellow).SprintfFunc() warning = color.New(color.FgYellow).SprintfFunc()
info = color.New(color.FgMagenta).SprintfFunc() info = color.New(color.FgMagenta).SprintfFunc()
hiwhite = color.New(color.FgHiWhite).SprintfFunc() hiwhite = color.New(color.FgHiWhite).SprintfFunc()
@ -102,7 +105,6 @@ type appContext struct {
host string host string
port int port int
version string version string
quit chan os.Signal
URLBase string URLBase string
updater *Updater updater *Updater
newUpdate bool // Whether whatever's in update is new. newUpdate bool // Whether whatever's in update is new.
@ -152,6 +154,7 @@ func test(app *appContext) {
} }
func start(asDaemon, firstCall bool) { func start(asDaemon, firstCall bool) {
RESTARTLISTENERCOUNT = 0
RUNNING = true RUNNING = true
defer func() { RUNNING = false }() defer func() { RUNNING = false }()
@ -250,7 +253,7 @@ func start(asDaemon, firstCall bool) {
app.err.Fatalf("Couldn't establish socket connection at %s\n", SOCK) app.err.Fatalf("Couldn't establish socket connection at %s\n", SOCK)
} }
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt) signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() { go func() {
<-c <-c
os.Remove(SOCK) os.Remove(SOCK)
@ -578,15 +581,10 @@ func start(asDaemon, firstCall bool) {
} else { } else {
app.info.Printf("Loaded @ %s", address) app.info.Printf("Loaded @ %s", address)
} }
app.quit = make(chan os.Signal)
signal.Notify(app.quit, os.Interrupt) waitForRestart()
go func() {
for range app.quit { app.info.Printf("Restart/Quit signal received, give me a second!")
app.shutdown()
}
}()
for range RESTART {
println("got it too!")
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel() defer cancel()
if err := SRV.Shutdown(ctx); err != nil { if err := SRV.Shutdown(ctx); err != nil {
@ -595,23 +593,26 @@ func start(asDaemon, firstCall bool) {
app.info.Println("Server shut down.") app.info.Println("Server shut down.")
return return
} }
}
func (app *appContext) shutdown() { func shutdown() {
app.info.Println("Shutting down...")
QUIT = true QUIT = true
RESTART <- true RESTART <- true
for { // Safety Sleep (Ensure shutdown tasks get done)
if RUNNING { time.Sleep(time.Second)
continue
} }
cntx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel() func (app *appContext) shutdown() {
if err := SRV.Shutdown(cntx); err != nil { app.info.Println("Shutting down...")
app.err.Fatalf("Server shutdown error: %s", err) shutdown()
} }
os.Exit(1) // Receives a restart signal and re-broadcasts it for other components.
func waitForRestart() {
RESTARTLISTENERCOUNT++
<-RESTART
RESTARTLISTENERCOUNT--
if RESTARTLISTENERCOUNT > 0 {
RESTART <- true
} }
} }
@ -686,6 +687,15 @@ func main() {
TEST = true TEST = true
} }
loadFilesystems() loadFilesystems()
quit := make(chan os.Signal, 0)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
// defer close(quit)
go func() {
<-quit
shutdown()
}()
if flagPassed("start") { if flagPassed("start") {
args := []string{} args := []string{}
for i, f := range os.Args { for i, f := range os.Args {
@ -760,7 +770,7 @@ You can then run:
start(false, true) start(false, true)
for { for {
if QUIT { if QUIT {
continue break
} }
printVersion() printVersion()
start(false, false) start(false, false)

@ -46,7 +46,7 @@ func (app *appContext) StartPWR() {
app.err.Printf("Failed to start password reset daemon: %s", err) app.err.Printf("Failed to start password reset daemon: %s", err)
} }
<-RESTART waitForRestart()
} }
// PasswordReset represents a passwordreset-xyz.json file generated by Jellyfin. // PasswordReset represents a passwordreset-xyz.json file generated by Jellyfin.

@ -1,4 +1,4 @@
// +build !windows //go:build !windows
package main package main
@ -11,9 +11,10 @@ import (
func (app *appContext) HardRestart() error { func (app *appContext) HardRestart() error {
defer func() { defer func() {
quit := make(chan os.Signal, 0)
if r := recover(); r != nil { if r := recover(); r != nil {
signal.Notify(app.quit, os.Interrupt) signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
<-app.quit <-quit
} }
}() }()
args := os.Args args := os.Args

@ -8,6 +8,7 @@ import (
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
"time"
"github.com/getlantern/systray" "github.com/getlantern/systray"
) )
@ -26,6 +27,8 @@ func onExit() {
if RUNNING { if RUNNING {
QUIT = true QUIT = true
RESTART <- true RESTART <- true
// Safety Sleep (Ensure shutdown tasks get done)
time.Sleep(time.Second)
} }
os.Remove(SOCK) os.Remove(SOCK)
} }

Loading…
Cancel
Save