Skip to content

Commit 169b3fb

Browse files
committed
feat: reload config on SIGUSR1
- Allows quick reloading with SIGUSR1 without when filesytem watch is not available like on a default docker setup `docker kill -s SIGUSR1` - Also refactored the signal handling in a single logical unit Signed-off-by: blob42 <[email protected]>
1 parent dea9873 commit 169b3fb

File tree

3 files changed

+60
-31
lines changed

3 files changed

+60
-31
lines changed

docs/configuration.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,3 +384,14 @@ hooks:
384384
preload:
385385
- "llama"
386386
```
387+
388+
## Hot Reloading Configuration
389+
390+
Trigger a configuration reload by sending `SIGUSR1` to the process:
391+
392+
- **With Docker** (if container is named `llama-swap`):
393+
```bash
394+
docker kill -s SIGUSR1 llama-swap
395+
```
396+
397+
For real-time file system monitoring and automatic restarts on config changes, see [restart-on-config-change](./examples/restart-on-config-change/README.md).
Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,41 @@
11
# Restart llama-swap on config change
22

3-
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.
3+
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 `SIGUSR1` signal to `llama-swap` to trigger a config file reload when it detects a change.
44

55
```bash
66
#!/bin/bash
77
#
88
# A simple watch and restart llama-swap when its configuration
99
# file changes. Useful for trying out configuration changes
1010
# without manually restarting the server each time.
11+
12+
# For docker users, consider replacing:
13+
# `kill -USR1 $PID` with `docker kill -s SIGUSR1 container_name`
14+
1115
if [ -z "$1" ]; then
1216
echo "Usage: $0 <path to config.yaml>"
1317
exit 1
1418
fi
1519

16-
while true; do
17-
# Start the process again
18-
./llama-swap-linux-amd64 -config $1 -listen :1867 &
19-
PID=$!
20-
echo "Started llama-swap with PID $PID"
20+
# Start the process once
21+
./llama-swap-linux-amd64 -config $1 -listen :1867 &
22+
PID=$!
23+
echo "Started llama-swap with PID $PID"
2124

25+
while true; do
2226
# Wait for modifications in the specified directory or file
23-
inotifywait -e modify "$1"
27+
if ! inotifywait -e modify "$1" 2>/dev/null; then
28+
echo "Error: Failed to monitor file changes"
29+
break
30+
fi
2431

2532
# Check if process exists before sending signal
2633
if kill -0 $PID 2>/dev/null; then
27-
echo "Sending SIGTERM to $PID"
28-
kill -SIGTERM $PID
29-
wait $PID
34+
echo "Sending SIGUSR1 to $PID"
35+
kill -USR1 $PID
3036
else
3137
echo "Process $PID no longer exists"
38+
break
3239
fi
3340
sleep 1
3441
done
@@ -42,10 +49,10 @@ Started llama-swap with PID 495455
4249
Setting up watches.
4350
Watches established.
4451
llama-swap listening on :1867
45-
Sending SIGTERM to 495455
46-
Shutting down llama-swap
47-
Started llama-swap with PID 495486
48-
Setting up watches.
49-
Watches established.
50-
llama-swap listening on :1867
52+
...
53+
Sending SIGUSR1 to 495455
54+
Received SIGUSR1. Reloading configuration...
55+
Configuration Changed
56+
Configuration Reloaded
57+
...
5158
```

llama-swap.go

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func main() {
7777
// Setup channels for server management
7878
exitChan := make(chan struct{})
7979
sigChan := make(chan os.Signal, 1)
80-
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
80+
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)
8181

8282
// Create server with initial handler
8383
srv := &http.Server{
@@ -170,23 +170,34 @@ func main() {
170170
}()
171171
}
172172

173-
// shutdown on signal
173+
// shutdown on SIGINT/SIGTERM
174+
// reload config on SIGUSR1
174175
go func() {
175-
sig := <-sigChan
176-
fmt.Printf("Received signal %v, shutting down...\n", sig)
177-
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
178-
defer cancel()
179-
180-
if pm, ok := srv.Handler.(*proxy.ProxyManager); ok {
181-
pm.Shutdown()
182-
} else {
183-
fmt.Println("srv.Handler is not of type *proxy.ProxyManager")
184-
}
176+
for sig := range sigChan {
177+
switch sig {
178+
case syscall.SIGINT, syscall.SIGTERM:
179+
fmt.Printf("Received signal %v, shutting down...\n", sig)
180+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
181+
defer cancel()
182+
183+
if pm, ok := srv.Handler.(*proxy.ProxyManager); ok {
184+
pm.Shutdown()
185+
} else {
186+
fmt.Println("srv.Handler is not of type *proxy.ProxyManager")
187+
}
185188

186-
if err := srv.Shutdown(ctx); err != nil {
187-
fmt.Printf("Server shutdown error: %v\n", err)
189+
if err := srv.Shutdown(ctx); err != nil {
190+
fmt.Printf("Server shutdown error: %v\n", err)
191+
}
192+
close(exitChan)
193+
return
194+
case syscall.SIGUSR1:
195+
fmt.Println("Received SIGUSR1. Reloading configuration...")
196+
reloadProxyManager()
197+
default:
198+
log.Printf("Unhandled signal: %v", sig)
199+
}
188200
}
189-
close(exitChan)
190201
}()
191202

192203
// Start server

0 commit comments

Comments
 (0)