prevent duplicate reload request in same time
This commit is contained in:
parent
cee79ea4dd
commit
9b7bb78676
3 changed files with 34 additions and 9 deletions
|
|
@ -14,7 +14,7 @@ func reloadCommand() Definition {
|
||||||
if err := rt.ReloadConfig(); err != nil {
|
if err := rt.ReloadConfig(); err != nil {
|
||||||
return req.Reply("Failed to reload configuration: " + err.Error())
|
return req.Reply("Failed to reload configuration: " + err.Error())
|
||||||
}
|
}
|
||||||
return req.Reply("Configuration reloaded successfully!")
|
return req.Reply("Config reload triggered!")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -55,6 +56,7 @@ type services struct {
|
||||||
DeviceService *devices.Service
|
DeviceService *devices.Service
|
||||||
HealthServer *health.Server
|
HealthServer *health.Server
|
||||||
manualReloadChan chan struct{}
|
manualReloadChan chan struct{}
|
||||||
|
reloading atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type startupBlockedProvider struct {
|
type startupBlockedProvider struct {
|
||||||
|
|
@ -122,11 +124,16 @@ func Run(debug bool, configPath string, allowEmptyStartup bool) error {
|
||||||
manualReloadChan := make(chan struct{}, 1)
|
manualReloadChan := make(chan struct{}, 1)
|
||||||
runningServices.manualReloadChan = manualReloadChan
|
runningServices.manualReloadChan = manualReloadChan
|
||||||
reloadTrigger := func() error {
|
reloadTrigger := func() error {
|
||||||
|
if !runningServices.reloading.CompareAndSwap(false, true) {
|
||||||
|
return fmt.Errorf("reload already in progress")
|
||||||
|
}
|
||||||
select {
|
select {
|
||||||
case manualReloadChan <- struct{}{}:
|
case manualReloadChan <- struct{}{}:
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("reload already in progress")
|
// Should not happen, but reset flag if channel is full
|
||||||
|
runningServices.reloading.Store(false)
|
||||||
|
return fmt.Errorf("reload already queued")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runningServices.HealthServer.SetReloadFunc(reloadTrigger)
|
runningServices.HealthServer.SetReloadFunc(reloadTrigger)
|
||||||
|
|
@ -158,7 +165,11 @@ func Run(debug bool, configPath string, allowEmptyStartup bool) error {
|
||||||
shutdownGateway(runningServices, agentLoop, provider, true)
|
shutdownGateway(runningServices, agentLoop, provider, true)
|
||||||
return nil
|
return nil
|
||||||
case newCfg := <-configReloadChan:
|
case newCfg := <-configReloadChan:
|
||||||
err := handleConfigReload(ctx, agentLoop, newCfg, &provider, runningServices, msgBus, allowEmptyStartup)
|
if !runningServices.reloading.CompareAndSwap(false, true) {
|
||||||
|
logger.Warn("Config reload skipped: another reload is in progress")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := executeReload(ctx, agentLoop, newCfg, &provider, runningServices, msgBus, allowEmptyStartup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("Config reload failed: %v", err)
|
logger.Errorf("Config reload failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -167,13 +178,15 @@ func Run(debug bool, configPath string, allowEmptyStartup bool) error {
|
||||||
newCfg, err := config.LoadConfig(configPath)
|
newCfg, err := config.LoadConfig(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("Error loading config for manual reload: %v", err)
|
logger.Errorf("Error loading config for manual reload: %v", err)
|
||||||
|
runningServices.reloading.Store(false)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err = newCfg.ValidateModelList(); err != nil {
|
if err = newCfg.ValidateModelList(); err != nil {
|
||||||
logger.Errorf("Config validation failed: %v", err)
|
logger.Errorf("Config validation failed: %v", err)
|
||||||
|
runningServices.reloading.Store(false)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = handleConfigReload(ctx, agentLoop, newCfg, &provider, runningServices, msgBus, allowEmptyStartup)
|
err = executeReload(ctx, agentLoop, newCfg, &provider, runningServices, msgBus, allowEmptyStartup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("Manual reload failed: %v", err)
|
logger.Errorf("Manual reload failed: %v", err)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -183,6 +196,19 @@ func Run(debug bool, configPath string, allowEmptyStartup bool) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func executeReload(
|
||||||
|
ctx context.Context,
|
||||||
|
agentLoop *agent.AgentLoop,
|
||||||
|
newCfg *config.Config,
|
||||||
|
provider *providers.LLMProvider,
|
||||||
|
runningServices *services,
|
||||||
|
msgBus *bus.MessageBus,
|
||||||
|
allowEmptyStartup bool,
|
||||||
|
) error {
|
||||||
|
defer runningServices.reloading.Store(false)
|
||||||
|
return handleConfigReload(ctx, agentLoop, newCfg, provider, runningServices, msgBus, allowEmptyStartup)
|
||||||
|
}
|
||||||
|
|
||||||
func createStartupProvider(
|
func createStartupProvider(
|
||||||
cfg *config.Config,
|
cfg *config.Config,
|
||||||
allowEmptyStartup bool,
|
allowEmptyStartup bool,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ type Server struct {
|
||||||
checks map[string]Check
|
checks map[string]Check
|
||||||
startTime time.Time
|
startTime time.Time
|
||||||
reloadFunc func() error
|
reloadFunc func() error
|
||||||
reloadMu sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Check struct {
|
type Check struct {
|
||||||
|
|
@ -111,8 +110,8 @@ func (s *Server) RegisterCheck(name string, checkFn func() (bool, string)) {
|
||||||
|
|
||||||
// SetReloadFunc sets the callback function for config reload.
|
// SetReloadFunc sets the callback function for config reload.
|
||||||
func (s *Server) SetReloadFunc(fn func() error) {
|
func (s *Server) SetReloadFunc(fn func() error) {
|
||||||
s.reloadMu.Lock()
|
s.mu.Lock()
|
||||||
defer s.reloadMu.Unlock()
|
defer s.mu.Unlock()
|
||||||
s.reloadFunc = fn
|
s.reloadFunc = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,9 +123,9 @@ func (s *Server) reloadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.reloadMu.Lock()
|
s.mu.Lock()
|
||||||
reloadFunc := s.reloadFunc
|
reloadFunc := s.reloadFunc
|
||||||
s.reloadMu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
if reloadFunc == nil {
|
if reloadFunc == nil {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue