mirror of
https://github.com/laoxong/nofx.git
synced 2026-06-04 09:58:22 +08:00
fix: auto-restart trader on config update and add scan interval debug logs
- RemoveTrader now stops running trader before removing from memory - handleUpdateTrader auto-restarts trader if it was running before update - Add debug logs to trace scan_interval_minutes through update/save/load flow
This commit is contained in:
+27
-3
@@ -779,11 +779,13 @@ func (s *Server) handleUpdateTrader(c *gin.Context) {
|
||||
|
||||
// Set scan interval, allow updates
|
||||
scanIntervalMinutes := req.ScanIntervalMinutes
|
||||
logger.Infof("📊 Update trader scan_interval: req=%d, existing=%d", req.ScanIntervalMinutes, existingTrader.ScanIntervalMinutes)
|
||||
if scanIntervalMinutes <= 0 {
|
||||
scanIntervalMinutes = existingTrader.ScanIntervalMinutes // Keep original value
|
||||
} else if scanIntervalMinutes < 3 {
|
||||
scanIntervalMinutes = 3
|
||||
}
|
||||
logger.Infof("📊 Final scan_interval_minutes: %d", scanIntervalMinutes)
|
||||
|
||||
// Set system prompt template
|
||||
systemPromptTemplate := req.SystemPromptTemplate
|
||||
@@ -818,16 +820,26 @@ func (s *Server) handleUpdateTrader(c *gin.Context) {
|
||||
IsRunning: existingTrader.IsRunning, // Keep original value
|
||||
}
|
||||
|
||||
// Check if trader was running before update (we'll restart it after)
|
||||
wasRunning := false
|
||||
if existingMemTrader, memErr := s.traderManager.GetTrader(traderID); memErr == nil {
|
||||
status := existingMemTrader.GetStatus()
|
||||
if running, ok := status["is_running"].(bool); ok && running {
|
||||
wasRunning = true
|
||||
logger.Infof("🔄 Trader %s was running, will restart with new config after update", traderID)
|
||||
}
|
||||
}
|
||||
|
||||
// Update database
|
||||
logger.Infof("🔄 Updating trader: ID=%s, Name=%s, AIModelID=%s, StrategyID=%s, req.StrategyID=%s",
|
||||
traderRecord.ID, traderRecord.Name, traderRecord.AIModelID, traderRecord.StrategyID, req.StrategyID)
|
||||
logger.Infof("🔄 Updating trader: ID=%s, Name=%s, AIModelID=%s, StrategyID=%s, ScanInterval=%d min",
|
||||
traderRecord.ID, traderRecord.Name, traderRecord.AIModelID, traderRecord.StrategyID, scanIntervalMinutes)
|
||||
err = s.store.Trader().Update(traderRecord)
|
||||
if err != nil {
|
||||
SafeInternalError(c, "Failed to update trader", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Remove old trader from memory first to ensure fresh config is loaded
|
||||
// Remove old trader from memory first (this also stops if running)
|
||||
s.traderManager.RemoveTrader(traderID)
|
||||
|
||||
// Reload traders into memory with fresh config
|
||||
@@ -836,6 +848,18 @@ func (s *Server) handleUpdateTrader(c *gin.Context) {
|
||||
logger.Infof("⚠️ Failed to reload user traders into memory: %v", err)
|
||||
}
|
||||
|
||||
// If trader was running before, restart it with new config
|
||||
if wasRunning {
|
||||
if reloadedTrader, getErr := s.traderManager.GetTrader(traderID); getErr == nil {
|
||||
go func() {
|
||||
logger.Infof("▶️ Restarting trader %s with new config...", traderID)
|
||||
if runErr := reloadedTrader.Run(); runErr != nil {
|
||||
logger.Infof("❌ Trader %s runtime error: %v", traderID, runErr)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
logger.Infof("✓ Trader updated successfully: %s (model: %s, exchange: %s, strategy: %s)", req.Name, req.AIModelID, req.ExchangeID, strategyID)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
|
||||
@@ -410,11 +410,18 @@ func (tm *TraderManager) GetTopTradersData() (map[string]interface{}, error) {
|
||||
|
||||
// RemoveTrader removes a trader from memory (does not affect database)
|
||||
// Used to force reload when updating trader configuration
|
||||
// If the trader is running, it will be stopped first
|
||||
func (tm *TraderManager) RemoveTrader(traderID string) {
|
||||
tm.mu.Lock()
|
||||
defer tm.mu.Unlock()
|
||||
|
||||
if _, exists := tm.traders[traderID]; exists {
|
||||
if t, exists := tm.traders[traderID]; exists {
|
||||
// Stop the trader if it's running (this ensures the goroutine exits)
|
||||
status := t.GetStatus()
|
||||
if isRunning, ok := status["is_running"].(bool); ok && isRunning {
|
||||
logger.Infof("⏹ Stopping trader %s before removing from memory...", traderID)
|
||||
t.Stop()
|
||||
}
|
||||
delete(tm.traders, traderID)
|
||||
logger.Infof("✓ Trader %s removed from memory", traderID)
|
||||
}
|
||||
@@ -664,6 +671,9 @@ func (tm *TraderManager) addTraderFromStore(traderCfg *store.Trader, aiModelCfg
|
||||
StrategyConfig: strategyConfig,
|
||||
}
|
||||
|
||||
logger.Infof("📊 Loading trader %s: ScanIntervalMinutes=%d (from DB), ScanInterval=%v",
|
||||
traderCfg.Name, traderCfg.ScanIntervalMinutes, traderConfig.ScanInterval)
|
||||
|
||||
// Set API keys based on exchange type (convert EncryptedString to string)
|
||||
switch exchangeCfg.ExchangeType {
|
||||
case "binance":
|
||||
|
||||
@@ -124,6 +124,9 @@ func (s *TraderStore) Update(trader *Trader) error {
|
||||
}
|
||||
if trader.ScanIntervalMinutes > 0 {
|
||||
updates["scan_interval_minutes"] = trader.ScanIntervalMinutes
|
||||
fmt.Printf("📊 TraderStore.Update: scan_interval_minutes=%d will be saved\n", trader.ScanIntervalMinutes)
|
||||
} else {
|
||||
fmt.Printf("⚠️ TraderStore.Update: scan_interval_minutes=%d (<=0, NOT updating)\n", trader.ScanIntervalMinutes)
|
||||
}
|
||||
|
||||
return s.db.Model(&Trader{}).
|
||||
|
||||
Reference in New Issue
Block a user