mirror of
https://github.com/la5nta/pat
synced 2026-08-07 22:32:06 -04:00
parent
6fe9a4f403
commit
addbefa74a
3 changed files with 83 additions and 14 deletions
58
main.go
58
main.go
|
|
@ -9,13 +9,14 @@ import (
|
|||
"context"
|
||||
"embed"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/la5nta/pat/api"
|
||||
"github.com/la5nta/pat/app"
|
||||
"github.com/la5nta/pat/cfg"
|
||||
"github.com/la5nta/pat/cli"
|
||||
"github.com/la5nta/pat/internal/buildinfo"
|
||||
"github.com/la5nta/pat/internal/directories"
|
||||
|
|
@ -66,30 +67,59 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
sig := notifySignals()
|
||||
|
||||
// Run app in a loop for config reloading
|
||||
for runApp(opts, cmd, args, sig) {
|
||||
fmt.Fprintln(os.Stderr, "Reloading application...")
|
||||
}
|
||||
}
|
||||
|
||||
func runApp(opts app.Options, cmd app.Command, args []string, sig <-chan os.Signal) bool {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
a := app.New(opts)
|
||||
defer a.Close()
|
||||
|
||||
// Graceful shutdown by cancelling background context on interrupt.
|
||||
//
|
||||
// If we have an active connection, cancel that instead.
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, os.Interrupt)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
// Graceful shutdown/reload handling.
|
||||
shouldReload := make(chan bool, 1)
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(shouldReload)
|
||||
dirtyDisconnectNext := false // So we can do a dirty disconnect on the second interrupt
|
||||
for range sig {
|
||||
if ok := a.AbortActiveConnection(dirtyDisconnectNext); ok {
|
||||
dirtyDisconnectNext = !dirtyDisconnectNext
|
||||
continue
|
||||
for {
|
||||
select {
|
||||
case s := <-sig:
|
||||
switch {
|
||||
case isSIGHUP(s):
|
||||
// Avoid reloading of bad config
|
||||
if _, err := app.LoadConfig(opts.ConfigPath, cfg.DefaultConfig); err != nil {
|
||||
log.Printf("Ignoring live reload due to config error: %v", err)
|
||||
continue
|
||||
}
|
||||
cancel()
|
||||
shouldReload <- true
|
||||
return
|
||||
default:
|
||||
if ok := a.AbortActiveConnection(dirtyDisconnectNext); ok {
|
||||
dirtyDisconnectNext = !dirtyDisconnectNext
|
||||
continue
|
||||
}
|
||||
cancel()
|
||||
shouldReload <- false
|
||||
return
|
||||
}
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
// Run the app
|
||||
a.Run(ctx, cmd, args)
|
||||
close(done)
|
||||
return <-shouldReload
|
||||
}
|
||||
|
||||
func optionsSet(opts *app.Options) *pflag.FlagSet {
|
||||
|
|
|
|||
21
sighup_unix.go
Normal file
21
sighup_unix.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2022 Martin Hebnes Pedersen (LA5NTA). All rights reserved.
|
||||
// Use of this source code is governed by the MIT-license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//go:build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func notifySignals() <-chan os.Signal {
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, os.Interrupt, syscall.SIGHUP)
|
||||
return sig
|
||||
}
|
||||
|
||||
func isSIGHUP(s os.Signal) bool { return s == syscall.SIGHUP }
|
||||
18
sighup_windows.go
Normal file
18
sighup_windows.go
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2022 Martin Hebnes Pedersen (LA5NTA). All rights reserved.
|
||||
// Use of this source code is governed by the MIT-license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
)
|
||||
|
||||
func notifySignals(sig chan<- os.Signal) {
|
||||
signal.Notify(sig, os.Interrupt)
|
||||
}
|
||||
|
||||
func isSIGHUP(s os.Signal) bool { return false }
|
||||
Loading…
Add table
Add a link
Reference in a new issue