Skip to content

Commit 3cc09c7

Browse files
committed
feat: config hot-reload
1 parent 98aebb6 commit 3cc09c7

File tree

2 files changed

+28
-50
lines changed

2 files changed

+28
-50
lines changed

llama-swap.go

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ func main() {
5353
if err != nil {
5454
log.Printf("Error getting absolute path for config: %v. File watching disabled.", err)
5555
} else {
56-
go watchConfigFile(absConfigPath, proxyManager)
56+
var proxyManagerPtr = &proxyManager
57+
go watchConfigFile(absConfigPath, proxyManagerPtr, listenStr)
5758
}
5859
}
5960

@@ -73,8 +74,8 @@ func main() {
7374
}
7475
}
7576

76-
// watchConfigFile monitors the configuration file for changes and triggers a reload.
77-
func watchConfigFile(configPath string, pm *proxy.ProxyManager) {
77+
// watchConfigFile monitors the configuration file for changes and recreates the ProxyManager with the new config.
78+
func watchConfigFile(configPath string, pm **proxy.ProxyManager, listenStr *string) {
7879
watcher, err := fsnotify.NewWatcher()
7980
if err != nil {
8081
log.Printf("Error creating file watcher: %v. File watching disabled.", err)
@@ -109,11 +110,31 @@ func watchConfigFile(configPath string, pm *proxy.ProxyManager) {
109110
}
110111
debounceTimer = time.AfterFunc(debounceDuration, func() {
111112
log.Printf("Config file modified: %s, attempting reload...", event.Name)
112-
if err := pm.ReloadConfig(configPath); err != nil {
113-
log.Printf("Error reloading config: %v", err)
114-
} else {
115-
log.Println("Config reloaded successfully.")
113+
114+
// Load new configuration
115+
newConfig, err := proxy.LoadConfig(configPath)
116+
if err != nil {
117+
log.Printf("Error loading new config: %v", err)
118+
return
116119
}
120+
121+
// Stop and cleanup old ProxyManager
122+
oldPM := *pm
123+
log.Println("Shutting down old ProxyManager instance before reload...")
124+
oldPM.Shutdown()
125+
126+
// Create new ProxyManager with new config
127+
newPM := proxy.New(newConfig)
128+
*pm = newPM
129+
130+
// Start serving with new ProxyManager
131+
go func() {
132+
if err := newPM.Run(*listenStr); err != nil {
133+
log.Printf("Server error after config reload: %v", err)
134+
}
135+
}()
136+
137+
log.Println("Config reloaded successfully.")
117138
})
118139
}
119140
case err, ok := <-watcher.Errors:

proxy/proxymanager.go

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -196,49 +196,6 @@ func (pm *ProxyManager) HandlerFunc(w http.ResponseWriter, r *http.Request) {
196196
pm.ginEngine.ServeHTTP(w, r)
197197
}
198198

199-
// ReloadConfig loads a new configuration file, stops all current processes,
200-
// and updates the manager's internal configuration.
201-
func (pm *ProxyManager) ReloadConfig(configPath string) error {
202-
pm.proxyLogger.Debugf("Attempting to reload configuration from: %s", configPath)
203-
204-
newConfig, err := LoadConfig(configPath)
205-
if err != nil {
206-
return fmt.Errorf("failed to load new config: %w", err)
207-
}
208-
209-
// Update log level based on new config
210-
switch strings.ToLower(strings.TrimSpace(newConfig.LogLevel)) {
211-
case "debug":
212-
pm.proxyLogger.SetLogLevel(LevelDebug)
213-
pm.upstreamLogger.SetLogLevel(LevelDebug)
214-
case "info":
215-
pm.proxyLogger.SetLogLevel(LevelInfo)
216-
pm.upstreamLogger.SetLogLevel(LevelInfo)
217-
case "warn":
218-
pm.proxyLogger.SetLogLevel(LevelWarn)
219-
pm.upstreamLogger.SetLogLevel(LevelWarn)
220-
case "error":
221-
pm.proxyLogger.SetLogLevel(LevelError)
222-
pm.upstreamLogger.SetLogLevel(LevelError)
223-
default:
224-
pm.proxyLogger.SetLogLevel(LevelInfo) // Default to info if invalid
225-
pm.upstreamLogger.SetLogLevel(LevelInfo)
226-
}
227-
// Log the new log level based on the config value
228-
pm.proxyLogger.Debugf("Log level set to %s based on reloaded config", strings.ToLower(strings.TrimSpace(newConfig.LogLevel)))
229-
230-
pm.Lock()
231-
defer pm.Unlock()
232-
233-
pm.proxyLogger.Info("Stopping all current upstream processes due to config reload...")
234-
pm.stopProcesses() // Call internal stop without lock
235-
236-
pm.config = newConfig
237-
pm.proxyLogger.Info("ProxyManager configuration updated.")
238-
239-
return nil
240-
}
241-
242199
// StopProcesses acquires a lock and stops all running upstream processes.
243200
// This is the public method safe for concurrent calls.
244201
func (pm *ProxyManager) StopProcesses() {

0 commit comments

Comments
 (0)