skywire
skywire copied to clipboard
visor flag to watch config for changes & reload on changes
it should be possible to have a flag for the visor to watch the config for changes and reload, at least selectively, on config changes.
For example, the Caddy server has both a caddy run --watch to watch the config and reload on changes, as well as caddy reload --config to explicitly reload from a (possibly different) config without watching it or automatically reloading.
here is an example implementation using fsnotify
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/fsnotify/fsnotify"
)
func main() {
// Start the process in a goroutine
go runProcess()
// Set up a signal handler to gracefully exit the program
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
// Set up a watcher to detect changes to the config file
watcher, err := fsnotify.NewWatcher()
if err != nil {
fmt.Printf("Error creating watcher: %s\n", err)
return
}
defer watcher.Close()
// Add the config file to the watcher
err = watcher.Add("/path/to/config/file")
if err != nil {
fmt.Printf("Error adding file to watcher: %s\n", err)
return
}
// Start a loop to watch for changes to the config file
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
if event.Op&fsnotify.Write == fsnotify.Write {
fmt.Println("Config file changed, reloading process...")
// Send a signal to the process to gracefully exit
err := syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
if err != nil {
fmt.Printf("Error sending signal to process: %s\n", err)
}
// Wait for the process to exit
time.Sleep(1 * time.Second)
// Restart the process
go runProcess()
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
fmt.Printf("Error watching file: %s\n", err)
case sig := <-sigs:
fmt.Printf("Received signal %s, exiting...\n", sig)
// Send a signal to the process to gracefully exit
err := syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
if err != nil {
fmt.Printf("Error sending signal to process: %s\n", err)
}
// Wait for the process to exit
time.Sleep(1 * time.Second)
return
}
}
}
func runProcess() {
// Replace this with your actual process code
for {
fmt.Println("Running process...")
time.Sleep(5 * time.Second)
}
}
Here is an example implementation using spf13/viper
package main
import (
"fmt"
"time"
"github.com/spf13/viper"
)
func main() {
// Set up Viper to read from a config file
viper.SetConfigFile("/path/to/config/file")
if err := viper.ReadInConfig(); err != nil {
fmt.Printf("Error reading config file: %s\n", err)
return
}
// Watch for changes to the config file
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed, reloading...")
// Replace this with your actual code to handle the updated configuration
})
// Run your program logic here
for {
fmt.Println("Running program...")
time.Sleep(5 * time.Second)
}
}