add reloading and stopping from tsctl
This commit is contained in:
70
cmd/reload.go
Normal file
70
cmd/reload.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"git.oblat.lv/alex/triggerssmith/internal/vars"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var optsReloadCmd = struct {
|
||||
Debug *bool
|
||||
PID *int
|
||||
}{}
|
||||
|
||||
func readPID(path string) (int, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
s := strings.TrimSpace(string(data))
|
||||
|
||||
pid, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return pid, nil
|
||||
}
|
||||
|
||||
var reloadCmd = &cobra.Command{
|
||||
Use: "reload",
|
||||
Short: "Reload active server by PID using SIGHUP",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
slog.Error("Application panicked", slog.Any("error", r))
|
||||
}
|
||||
}()
|
||||
// configure logger
|
||||
if *optsReloadCmd.Debug {
|
||||
slog.SetDefault(slog.New(slog.NewTextHandler(cmd.OutOrStdout(), &slog.HandlerOptions{Level: slog.LevelDebug, AddSource: true})))
|
||||
} else {
|
||||
slog.SetDefault(slog.New(slog.NewTextHandler(cmd.OutOrStdout(), &slog.HandlerOptions{Level: slog.LevelInfo})))
|
||||
}
|
||||
pid, err := readPID(vars.PID_PATH)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
*optsReloadCmd.PID = pid
|
||||
slog.Debug("restarting server", slog.Int("pid", *optsReloadCmd.PID))
|
||||
proc, err := os.FindProcess(*optsReloadCmd.PID)
|
||||
if err != nil {
|
||||
slog.Error("failed to find process", slog.Int("pid", *optsReloadCmd.PID), slog.String("err", err.Error()))
|
||||
}
|
||||
proc.Signal(syscall.SIGHUP)
|
||||
slog.Debug("done")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
optsReloadCmd.Debug = reloadCmd.Flags().BoolP("debug", "d", false, "Enable debug logs")
|
||||
optsReloadCmd.PID = reloadCmd.Flags().IntP("pid", "p", -1, "Define server PID")
|
||||
rootCmd.AddCommand(reloadCmd)
|
||||
}
|
||||
114
cmd/serve.go
114
cmd/serve.go
@@ -5,14 +5,18 @@ import (
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
application "git.oblat.lv/alex/triggerssmith/internal/app"
|
||||
"git.oblat.lv/alex/triggerssmith/internal/config"
|
||||
"git.oblat.lv/alex/triggerssmith/internal/vars"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var opts = struct {
|
||||
var optsServeCmd = struct {
|
||||
ConfigPath *string
|
||||
Debug *bool
|
||||
}{}
|
||||
@@ -38,29 +42,49 @@ func loggingMiddleware(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func writePID(path string) error {
|
||||
pid := os.Getpid()
|
||||
|
||||
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = fmt.Fprintf(f, "%d\n", pid)
|
||||
return err
|
||||
}
|
||||
|
||||
var serveCmd = &cobra.Command{
|
||||
Use: "serve",
|
||||
Short: "Start the server",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// defer func() {
|
||||
// if r := recover(); r != nil {
|
||||
// slog.Error("Application panicked", slog.Any("error", r))
|
||||
// }
|
||||
// }()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
slog.Error("Application panicked", slog.Any("error", r))
|
||||
os.Exit(-1)
|
||||
}
|
||||
}()
|
||||
// configure logger
|
||||
if *opts.Debug {
|
||||
if *optsServeCmd.Debug {
|
||||
slog.SetDefault(slog.New(slog.NewTextHandler(cmd.OutOrStdout(), &slog.HandlerOptions{Level: slog.LevelDebug, AddSource: true})))
|
||||
} else {
|
||||
slog.SetDefault(slog.New(slog.NewTextHandler(cmd.OutOrStdout(), &slog.HandlerOptions{Level: slog.LevelInfo})))
|
||||
}
|
||||
|
||||
slog.Debug("Starting server")
|
||||
pid := os.Getpid()
|
||||
slog.Debug("Starting server", slog.Int("pid", pid))
|
||||
if err := writePID(vars.PID_PATH); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
slog.Debug("created pid file", slog.String("path", vars.PID_PATH))
|
||||
defer os.Remove(vars.PID_PATH)
|
||||
|
||||
// load config
|
||||
slog.Debug("Reading configuration", slog.String("path", *opts.ConfigPath))
|
||||
cfg, err := config.LoadConfig(*opts.ConfigPath)
|
||||
slog.Debug("Reading configuration", slog.String("path", *optsServeCmd.ConfigPath))
|
||||
cfg, err := config.LoadConfig(*optsServeCmd.ConfigPath)
|
||||
if err != nil {
|
||||
slog.Error("Failed to load configuration", slog.String("path", *opts.ConfigPath), slog.String("error", err.Error()))
|
||||
slog.Error("Failed to load configuration", slog.String("path", *optsServeCmd.ConfigPath), slog.String("error", err.Error()))
|
||||
return
|
||||
}
|
||||
slog.Debug("Configuration loaded", slog.Any("config", cfg))
|
||||
@@ -73,39 +97,6 @@ var serveCmd = &cobra.Command{
|
||||
}
|
||||
app.LoadConfiguration(cfg)
|
||||
|
||||
/*
|
||||
// setup handlers
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// static files
|
||||
staticPath := cfg.Server.StaticFilesPath
|
||||
slog.Debug("Setting up static file server", slog.String("path", staticPath))
|
||||
fs := http.FileServer(http.Dir(staticPath))
|
||||
mux.Handle("/static/", http.StripPrefix("/static/", fs))
|
||||
handler := loggingMiddleware(mux)
|
||||
*/
|
||||
|
||||
// start server
|
||||
/*addr := fmt.Sprintf("%s:%d", cfg.Server.Addr, cfg.Server.Port)
|
||||
slog.Debug("Binding listener", slog.String("address", addr))
|
||||
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
slog.Error("Failed to start listener", slog.String("address", addr), slog.String("error", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: handler,
|
||||
}
|
||||
|
||||
slog.Info("Server started", slog.String("address", addr))
|
||||
|
||||
if err := srv.Serve(ln); err != nil && err != http.ErrServerClosed {
|
||||
slog.Error("HTTP server stopped with error", slog.String("error", err.Error()))
|
||||
}*/
|
||||
|
||||
server := app.Server()
|
||||
mux := http.NewServeMux()
|
||||
|
||||
@@ -129,26 +120,49 @@ var serveCmd = &cobra.Command{
|
||||
slog.Info("Server started", slog.String("address", net.JoinHostPort(cfg.Server.Addr, fmt.Sprintf("%d", cfg.Server.Port))))
|
||||
}
|
||||
|
||||
sigch := make(chan os.Signal, 1)
|
||||
signal.Notify(sigch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
|
||||
for true {
|
||||
fmt.Scanln()
|
||||
sig := <-sigch
|
||||
slog.Debug("got signal", slog.Any("os.Signal", sig))
|
||||
switch sig {
|
||||
case syscall.SIGHUP:
|
||||
if err := config.ReloadConfig(cfg); err != nil {
|
||||
slog.Error("Failed to reload configuration", slog.String("error", err.Error()))
|
||||
} else {
|
||||
slog.Info("Configuration reloaded", slog.Any("config", cfg))
|
||||
slog.Info("Configuration reloaded")
|
||||
var addr = net.JoinHostPort(cfg.Server.Addr, fmt.Sprintf("%d", cfg.Server.Port))
|
||||
slog.Debug("New configuration", slog.Any("config", cfg))
|
||||
err = server.Reload(addr)
|
||||
if err != nil {
|
||||
slog.Error("Failed to restart server with new configuration", slog.String("error", err.Error()))
|
||||
} else {
|
||||
slog.Info("Server restarted with new configuration", slog.String("address", net.JoinHostPort(cfg.Server.Addr, fmt.Sprintf("%d", cfg.Server.Port))))
|
||||
}
|
||||
}
|
||||
case syscall.SIGINT:
|
||||
slog.Info("Stopping server by SIGINT")
|
||||
err := server.Stop()
|
||||
if err != nil {
|
||||
slog.Error("Failed to stop server", slog.String("err", err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Remove(vars.PID_PATH)
|
||||
return
|
||||
case syscall.SIGTERM:
|
||||
slog.Info("Stopping server by SIGTERM")
|
||||
err := server.Stop()
|
||||
if err != nil {
|
||||
slog.Error("Failed to stop server", slog.String("err", err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Remove(vars.PID_PATH)
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
opts.Debug = serveCmd.Flags().BoolP("debug", "d", false, "Enable debug logs")
|
||||
opts.ConfigPath = serveCmd.Flags().StringP("config", "c", "config.yaml", "Path to configuration file")
|
||||
optsServeCmd.Debug = serveCmd.Flags().BoolP("debug", "d", false, "Enable debug logs")
|
||||
optsServeCmd.ConfigPath = serveCmd.Flags().StringP("config", "c", "config.yaml", "Path to configuration file")
|
||||
rootCmd.AddCommand(serveCmd)
|
||||
}
|
||||
|
||||
51
cmd/stop.go
Normal file
51
cmd/stop.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"git.oblat.lv/alex/triggerssmith/internal/vars"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var optsStopCmd = struct {
|
||||
Debug *bool
|
||||
PID *int
|
||||
}{}
|
||||
|
||||
var stopCmd = &cobra.Command{
|
||||
Use: "stop",
|
||||
Short: "Stop active server by PID using SIGTERM",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
slog.Error("Application panicked", slog.Any("error", r))
|
||||
}
|
||||
}()
|
||||
// configure logger
|
||||
if *optsReloadCmd.Debug {
|
||||
slog.SetDefault(slog.New(slog.NewTextHandler(cmd.OutOrStdout(), &slog.HandlerOptions{Level: slog.LevelDebug, AddSource: true})))
|
||||
} else {
|
||||
slog.SetDefault(slog.New(slog.NewTextHandler(cmd.OutOrStdout(), &slog.HandlerOptions{Level: slog.LevelInfo})))
|
||||
}
|
||||
pid, err := readPID(vars.PID_PATH)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
*optsStopCmd.PID = pid
|
||||
slog.Debug("restarting server", slog.Int("pid", *optsStopCmd.PID))
|
||||
proc, err := os.FindProcess(*optsStopCmd.PID)
|
||||
if err != nil {
|
||||
slog.Error("failed to find process", slog.Int("pid", *optsStopCmd.PID), slog.String("err", err.Error()))
|
||||
}
|
||||
proc.Signal(syscall.SIGTERM)
|
||||
slog.Debug("done")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
optsStopCmd.Debug = stopCmd.Flags().BoolP("debug", "d", false, "Enable debug logs")
|
||||
optsStopCmd.PID = stopCmd.Flags().IntP("pid", "p", -1, "Define server PID")
|
||||
rootCmd.AddCommand(stopCmd)
|
||||
}
|
||||
@@ -249,7 +249,6 @@ func (ls *LiveServer) Stop() error {
|
||||
return ls.stop(inst)
|
||||
}
|
||||
|
||||
|
||||
func (ls *LiveServer) Reload(newAddr string) error {
|
||||
ls.mu.Lock()
|
||||
oldInstAny := ls.active.Load()
|
||||
@@ -448,7 +447,6 @@ func (ls *LiveServer) Reload(newAddr string) error {
|
||||
|
||||
// ls.setStatus(Status{ID: StatusStarting})
|
||||
|
||||
|
||||
// err := ls.Start()
|
||||
// if err != nil {
|
||||
// ls.active.Store(oldInstAny)
|
||||
|
||||
4
internal/vars/const.go
Normal file
4
internal/vars/const.go
Normal file
@@ -0,0 +1,4 @@
|
||||
package vars
|
||||
|
||||
const VAR_PATH = "/var/run/triggerssmith/"
|
||||
const PID_PATH = VAR_PATH + "serve.pid"
|
||||
Reference in New Issue
Block a user