diff --git a/docs/configuration.md b/docs/configuration.md index c253d408..fe697148 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -384,3 +384,14 @@ hooks: preload: - "llama" ``` + +## Hot Reloading Configuration + +Trigger a configuration reload by sending `SIGHUP` to the process: + +- **With Docker** (if container is named `llama-swap`): + ```bash + docker kill -s SIGHUP llama-swap + ``` + +For real-time file system monitoring and automatic restarts on config changes, see [restart-on-config-change](./examples/restart-on-config-change/README.md). diff --git a/docs/examples/restart-on-config-change/README.md b/docs/examples/restart-on-config-change/README.md index 1f67aea1..0fdb4585 100644 --- a/docs/examples/restart-on-config-change/README.md +++ b/docs/examples/restart-on-config-change/README.md @@ -1,6 +1,6 @@ # Restart llama-swap on config change -Sometimes editing the configuration file can take a bit of trail and error to get a model configuration tuned just right. The `watch-and-restart.sh` script can be used to watch `config.yaml` for changes and restart `llama-swap` when it detects a change. +Sometimes editing the configuration file can take a bit of trial and error to get a model configuration tuned just right. The `watch-and-restart.sh` script can be used to watch `config.yaml` for changes and send the `SIGHUP` signal to `llama-swap` to trigger a config file reload when it detects a change. ```bash #!/bin/bash @@ -8,27 +8,34 @@ Sometimes editing the configuration file can take a bit of trail and error to ge # A simple watch and restart llama-swap when its configuration # file changes. Useful for trying out configuration changes # without manually restarting the server each time. + +# For docker users, consider replacing: +# `kill -USR1 $PID` with `docker kill -s SIGHUP container_name` + if [ -z "$1" ]; then echo "Usage: $0 " exit 1 fi -while true; do - # Start the process again - ./llama-swap-linux-amd64 -config $1 -listen :1867 & - PID=$! - echo "Started llama-swap with PID $PID" +# Start the process once +./llama-swap-linux-amd64 -config $1 -listen :1867 & +PID=$! +echo "Started llama-swap with PID $PID" +while true; do # Wait for modifications in the specified directory or file - inotifywait -e modify "$1" + if ! inotifywait -e modify "$1" 2>/dev/null; then + echo "Error: Failed to monitor file changes" + break + fi # Check if process exists before sending signal if kill -0 $PID 2>/dev/null; then - echo "Sending SIGTERM to $PID" - kill -SIGTERM $PID - wait $PID + echo "Sending SIGHUP to $PID" + kill -USR1 $PID else echo "Process $PID no longer exists" + break fi sleep 1 done @@ -42,10 +49,10 @@ Started llama-swap with PID 495455 Setting up watches. Watches established. llama-swap listening on :1867 -Sending SIGTERM to 495455 -Shutting down llama-swap -Started llama-swap with PID 495486 -Setting up watches. -Watches established. -llama-swap listening on :1867 +... +Sending SIGHUP to 495455 +Received SIGHUP. Reloading configuration... +Configuration Changed +Configuration Reloaded +... ``` diff --git a/llama-swap.go b/llama-swap.go index 9706e07d..5f4bea83 100644 --- a/llama-swap.go +++ b/llama-swap.go @@ -77,7 +77,7 @@ func main() { // Setup channels for server management exitChan := make(chan struct{}) sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) + signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) // Create server with initial handler srv := &http.Server{ @@ -170,23 +170,34 @@ func main() { }() } - // shutdown on signal + // shutdown on SIGINT/SIGTERM + // reload config on SIGHUP go func() { - sig := <-sigChan - fmt.Printf("Received signal %v, shutting down...\n", sig) - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - - if pm, ok := srv.Handler.(*proxy.ProxyManager); ok { - pm.Shutdown() - } else { - fmt.Println("srv.Handler is not of type *proxy.ProxyManager") - } + for sig := range sigChan { + switch sig { + case syscall.SIGINT, syscall.SIGTERM: + fmt.Printf("Received signal %v, shutting down...\n", sig) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + + if pm, ok := srv.Handler.(*proxy.ProxyManager); ok { + pm.Shutdown() + } else { + fmt.Println("srv.Handler is not of type *proxy.ProxyManager") + } - if err := srv.Shutdown(ctx); err != nil { - fmt.Printf("Server shutdown error: %v\n", err) + if err := srv.Shutdown(ctx); err != nil { + fmt.Printf("Server shutdown error: %v\n", err) + } + close(exitChan) + return + case syscall.SIGHUP: + fmt.Println("Received SIGHUP. Reloading configuration...") + reloadProxyManager() + default: + log.Printf("Unhandled signal: %v", sig) + } } - close(exitChan) }() // Start server