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
|
// Set scan interval, allow updates
|
||||||
scanIntervalMinutes := req.ScanIntervalMinutes
|
scanIntervalMinutes := req.ScanIntervalMinutes
|
||||||
|
logger.Infof("📊 Update trader scan_interval: req=%d, existing=%d", req.ScanIntervalMinutes, existingTrader.ScanIntervalMinutes)
|
||||||
if scanIntervalMinutes <= 0 {
|
if scanIntervalMinutes <= 0 {
|
||||||
scanIntervalMinutes = existingTrader.ScanIntervalMinutes // Keep original value
|
scanIntervalMinutes = existingTrader.ScanIntervalMinutes // Keep original value
|
||||||
} else if scanIntervalMinutes < 3 {
|
} else if scanIntervalMinutes < 3 {
|
||||||
scanIntervalMinutes = 3
|
scanIntervalMinutes = 3
|
||||||
}
|
}
|
||||||
|
logger.Infof("📊 Final scan_interval_minutes: %d", scanIntervalMinutes)
|
||||||
|
|
||||||
// Set system prompt template
|
// Set system prompt template
|
||||||
systemPromptTemplate := req.SystemPromptTemplate
|
systemPromptTemplate := req.SystemPromptTemplate
|
||||||
@@ -818,16 +820,26 @@ func (s *Server) handleUpdateTrader(c *gin.Context) {
|
|||||||
IsRunning: existingTrader.IsRunning, // Keep original value
|
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
|
// Update database
|
||||||
logger.Infof("🔄 Updating trader: ID=%s, Name=%s, AIModelID=%s, StrategyID=%s, req.StrategyID=%s",
|
logger.Infof("🔄 Updating trader: ID=%s, Name=%s, AIModelID=%s, StrategyID=%s, ScanInterval=%d min",
|
||||||
traderRecord.ID, traderRecord.Name, traderRecord.AIModelID, traderRecord.StrategyID, req.StrategyID)
|
traderRecord.ID, traderRecord.Name, traderRecord.AIModelID, traderRecord.StrategyID, scanIntervalMinutes)
|
||||||
err = s.store.Trader().Update(traderRecord)
|
err = s.store.Trader().Update(traderRecord)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
SafeInternalError(c, "Failed to update trader", err)
|
SafeInternalError(c, "Failed to update trader", err)
|
||||||
return
|
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)
|
s.traderManager.RemoveTrader(traderID)
|
||||||
|
|
||||||
// Reload traders into memory with fresh config
|
// 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)
|
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)
|
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{
|
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)
|
// RemoveTrader removes a trader from memory (does not affect database)
|
||||||
// Used to force reload when updating trader configuration
|
// Used to force reload when updating trader configuration
|
||||||
|
// If the trader is running, it will be stopped first
|
||||||
func (tm *TraderManager) RemoveTrader(traderID string) {
|
func (tm *TraderManager) RemoveTrader(traderID string) {
|
||||||
tm.mu.Lock()
|
tm.mu.Lock()
|
||||||
defer tm.mu.Unlock()
|
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)
|
delete(tm.traders, traderID)
|
||||||
logger.Infof("✓ Trader %s removed from memory", traderID)
|
logger.Infof("✓ Trader %s removed from memory", traderID)
|
||||||
}
|
}
|
||||||
@@ -664,6 +671,9 @@ func (tm *TraderManager) addTraderFromStore(traderCfg *store.Trader, aiModelCfg
|
|||||||
StrategyConfig: strategyConfig,
|
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)
|
// Set API keys based on exchange type (convert EncryptedString to string)
|
||||||
switch exchangeCfg.ExchangeType {
|
switch exchangeCfg.ExchangeType {
|
||||||
case "binance":
|
case "binance":
|
||||||
|
|||||||
@@ -124,6 +124,9 @@ func (s *TraderStore) Update(trader *Trader) error {
|
|||||||
}
|
}
|
||||||
if trader.ScanIntervalMinutes > 0 {
|
if trader.ScanIntervalMinutes > 0 {
|
||||||
updates["scan_interval_minutes"] = trader.ScanIntervalMinutes
|
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{}).
|
return s.db.Model(&Trader{}).
|
||||||
|
|||||||
Reference in New Issue
Block a user