From b1cd01bf9b0b1e9637c0da36913fab34f188fb2c Mon Sep 17 00:00:00 2001 From: cryptooda Date: Sun, 9 Nov 2025 14:00:36 +0700 Subject: [PATCH] Fix backtest count --- .../Controllers/BacktestController.cs | 59 ++++++++++++++++++- .../Services/IBacktester.cs | 2 + .../Backtests/BacktestExecutorAdapter.cs | 2 + .../Backtests/Backtester.cs | 45 ++++++++++++++ .../Workers/BacktestComputeWorker.cs | 13 ++++ 5 files changed, 119 insertions(+), 2 deletions(-) diff --git a/src/Managing.Api/Controllers/BacktestController.cs b/src/Managing.Api/Controllers/BacktestController.cs index 2bd27326..06739a0c 100644 --- a/src/Managing.Api/Controllers/BacktestController.cs +++ b/src/Managing.Api/Controllers/BacktestController.cs @@ -36,6 +36,7 @@ public class BacktestController : BaseController private readonly IMoneyManagementService _moneyManagementService; private readonly IGeneticService _geneticService; private readonly IServiceScopeFactory _serviceScopeFactory; + private readonly ILogger _logger; /// /// Initializes a new instance of the class. @@ -54,7 +55,8 @@ public class BacktestController : BaseController IMoneyManagementService moneyManagementService, IGeneticService geneticService, IUserService userService, - IServiceScopeFactory serviceScopeFactory) : base(userService) + IServiceScopeFactory serviceScopeFactory, + ILogger logger) : base(userService) { _hubContext = hubContext; _backtester = backtester; @@ -62,6 +64,7 @@ public class BacktestController : BaseController _moneyManagementService = moneyManagementService; _geneticService = geneticService; _serviceScopeFactory = serviceScopeFactory; + _logger = logger; } /// @@ -673,7 +676,59 @@ public class BacktestController : BaseController Name = request.Name }; - await _backtester.InsertBundleBacktestRequestForUserAsync(user, bundleRequest, request.SaveAsTemplate); + // Save bundle request immediately (fast operation) + await _backtester.SaveBundleBacktestRequestAsync(user, bundleRequest); + + // If not saving as template, create jobs in background task + if (!request.SaveAsTemplate) + { + // Capture values for background task + var bundleRequestId = bundleRequest.RequestId; + var userId = user.Id; + + // Fire off background task to create jobs - don't await, return immediately + _ = Task.Run(async () => + { + try + { + using var scope = _serviceScopeFactory.CreateScope(); + var backtester = scope.ServiceProvider.GetRequiredService(); + var userService = scope.ServiceProvider.GetRequiredService(); + + // Reload user and bundle request to ensure we have the latest data + var reloadedUser = await userService.GetUserByIdAsync(userId); + if (reloadedUser == null) + { + _logger.LogWarning( + "User {UserId} not found when creating jobs for bundle request {BundleRequestId} in background", + userId, bundleRequestId); + return; + } + + var savedBundleRequest = backtester.GetBundleBacktestRequestByIdForUser(reloadedUser, bundleRequestId); + if (savedBundleRequest != null) + { + await backtester.CreateJobsForBundleRequestAsync(savedBundleRequest); + _logger.LogInformation( + "Successfully created jobs for bundle request {BundleRequestId} in background", + bundleRequestId); + } + else + { + _logger.LogWarning( + "Bundle request {BundleRequestId} not found when creating jobs in background", + bundleRequestId); + } + } + catch (Exception ex) + { + _logger.LogError(ex, + "Error creating jobs for bundle request {BundleRequestId} in background task", + bundleRequestId); + } + }); + } + return Ok(bundleRequest); } catch (Exception ex) diff --git a/src/Managing.Application.Abstractions/Services/IBacktester.cs b/src/Managing.Application.Abstractions/Services/IBacktester.cs index 2c22274d..71479ebe 100644 --- a/src/Managing.Application.Abstractions/Services/IBacktester.cs +++ b/src/Managing.Application.Abstractions/Services/IBacktester.cs @@ -85,6 +85,8 @@ namespace Managing.Application.Abstractions.Services Task DeleteBacktestsByFiltersAsync(User user, BacktestsFilter filter); Task InsertBundleBacktestRequestForUserAsync(User user, BundleBacktestRequest bundleRequest, bool saveAsTemplate = false); + Task SaveBundleBacktestRequestAsync(User user, BundleBacktestRequest bundleRequest); + Task CreateJobsForBundleRequestAsync(BundleBacktestRequest bundleRequest); IEnumerable GetBundleBacktestRequestsByUser(User user); Task> GetBundleBacktestRequestsByUserAsync(User user); BundleBacktestRequest? GetBundleBacktestRequestByIdForUser(User user, Guid id); diff --git a/src/Managing.Application/Backtests/BacktestExecutorAdapter.cs b/src/Managing.Application/Backtests/BacktestExecutorAdapter.cs index eba12943..e3ad0051 100644 --- a/src/Managing.Application/Backtests/BacktestExecutorAdapter.cs +++ b/src/Managing.Application/Backtests/BacktestExecutorAdapter.cs @@ -108,6 +108,8 @@ public class BacktestExecutorAdapter : IBacktester public Task DeleteBacktestsByRequestIdAsync(Guid requestId) => throw new NotImplementedException("Not available in compute worker"); public Task DeleteBacktestsByFiltersAsync(User user, BacktestsFilter filter) => throw new NotImplementedException("Not available in compute worker"); public Task InsertBundleBacktestRequestForUserAsync(User user, BundleBacktestRequest bundleRequest, bool saveAsTemplate = false) => throw new NotImplementedException("Not available in compute worker"); + public Task SaveBundleBacktestRequestAsync(User user, BundleBacktestRequest bundleRequest) => throw new NotImplementedException("Not available in compute worker"); + public Task CreateJobsForBundleRequestAsync(BundleBacktestRequest bundleRequest) => throw new NotImplementedException("Not available in compute worker"); public IEnumerable GetBundleBacktestRequestsByUser(User user) => throw new NotImplementedException("Not available in compute worker"); public Task> GetBundleBacktestRequestsByUserAsync(User user) => throw new NotImplementedException("Not available in compute worker"); public BundleBacktestRequest? GetBundleBacktestRequestByIdForUser(User user, Guid id) => throw new NotImplementedException("Not available in compute worker"); diff --git a/src/Managing.Application/Backtests/Backtester.cs b/src/Managing.Application/Backtests/Backtester.cs index f0242c84..d4c3ce2e 100644 --- a/src/Managing.Application/Backtests/Backtester.cs +++ b/src/Managing.Application/Backtests/Backtester.cs @@ -397,6 +397,51 @@ namespace Managing.Application.Backtests } } + /// + /// Saves a bundle backtest request without creating jobs. + /// Use this when you want to return immediately and create jobs in a background task. + /// + public async Task SaveBundleBacktestRequestAsync(User user, BundleBacktestRequest bundleRequest) + { + await _backtestRepository.InsertBundleBacktestRequestForUserAsync(user, bundleRequest); + } + + /// + /// Creates jobs for an existing bundle request asynchronously. + /// This method is intended to be called from a background task after the bundle request has been saved. + /// + public async Task CreateJobsForBundleRequestAsync(BundleBacktestRequest bundleRequest) + { + try + { + // Generate backtest requests from variants + var backtestRequests = await GenerateBacktestRequestsFromVariants(bundleRequest); + + if (backtestRequests != null && backtestRequests.Any()) + { + // Create jobs for all variants + await _jobService.CreateBundleJobsAsync(bundleRequest, backtestRequests); + + _logger.LogInformation( + "Created {JobCount} backtest jobs for bundle request {BundleRequestId}", + backtestRequests.Count, bundleRequest.RequestId); + } + else + { + _logger.LogWarning( + "No backtest requests generated for bundle request {BundleRequestId}", + bundleRequest.RequestId); + } + } + catch (Exception ex) + { + _logger.LogError(ex, + "Error creating jobs for bundle request {BundleRequestId}", + bundleRequest.RequestId); + throw; + } + } + /// /// Generates individual backtest requests from variant configuration /// diff --git a/src/Managing.Application/Workers/BacktestComputeWorker.cs b/src/Managing.Application/Workers/BacktestComputeWorker.cs index 4d2c04bb..27b630b4 100644 --- a/src/Managing.Application/Workers/BacktestComputeWorker.cs +++ b/src/Managing.Application/Workers/BacktestComputeWorker.cs @@ -122,6 +122,7 @@ public class BacktestComputeWorker : BackgroundService var executor = scope.ServiceProvider.GetRequiredService(); var userService = scope.ServiceProvider.GetRequiredService(); var exchangeService = scope.ServiceProvider.GetRequiredService(); + var agentSummaryRepository = scope.ServiceProvider.GetRequiredService(); try { @@ -192,6 +193,18 @@ public class BacktestComputeWorker : BackgroundService await jobRepository.UpdateAsync(job); + // Increment backtest count for the user's agent summary + try + { + await agentSummaryRepository.IncrementBacktestCountAsync(job.UserId); + _logger.LogDebug("Incremented backtest count for user {UserId}", job.UserId); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to increment backtest count for user {UserId}", job.UserId); + // Don't fail the job if this update fails + } + _logger.LogInformation( "Completed backtest job {JobId}. Score: {Score}, PnL: {PnL}", job.Id, result.Score, result.FinalPnl);