Fix backtest count

This commit is contained in:
2025-11-09 14:00:36 +07:00
parent 2ecd4a6306
commit b1cd01bf9b
5 changed files with 119 additions and 2 deletions

View File

@@ -36,6 +36,7 @@ public class BacktestController : BaseController
private readonly IMoneyManagementService _moneyManagementService; private readonly IMoneyManagementService _moneyManagementService;
private readonly IGeneticService _geneticService; private readonly IGeneticService _geneticService;
private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly ILogger<BacktestController> _logger;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BacktestController"/> class. /// Initializes a new instance of the <see cref="BacktestController"/> class.
@@ -54,7 +55,8 @@ public class BacktestController : BaseController
IMoneyManagementService moneyManagementService, IMoneyManagementService moneyManagementService,
IGeneticService geneticService, IGeneticService geneticService,
IUserService userService, IUserService userService,
IServiceScopeFactory serviceScopeFactory) : base(userService) IServiceScopeFactory serviceScopeFactory,
ILogger<BacktestController> logger) : base(userService)
{ {
_hubContext = hubContext; _hubContext = hubContext;
_backtester = backtester; _backtester = backtester;
@@ -62,6 +64,7 @@ public class BacktestController : BaseController
_moneyManagementService = moneyManagementService; _moneyManagementService = moneyManagementService;
_geneticService = geneticService; _geneticService = geneticService;
_serviceScopeFactory = serviceScopeFactory; _serviceScopeFactory = serviceScopeFactory;
_logger = logger;
} }
/// <summary> /// <summary>
@@ -673,7 +676,59 @@ public class BacktestController : BaseController
Name = request.Name 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<IBacktester>();
var userService = scope.ServiceProvider.GetRequiredService<IUserService>();
// 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); return Ok(bundleRequest);
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -85,6 +85,8 @@ namespace Managing.Application.Abstractions.Services
Task<int> DeleteBacktestsByFiltersAsync(User user, BacktestsFilter filter); Task<int> DeleteBacktestsByFiltersAsync(User user, BacktestsFilter filter);
Task InsertBundleBacktestRequestForUserAsync(User user, BundleBacktestRequest bundleRequest, bool saveAsTemplate = false); Task InsertBundleBacktestRequestForUserAsync(User user, BundleBacktestRequest bundleRequest, bool saveAsTemplate = false);
Task SaveBundleBacktestRequestAsync(User user, BundleBacktestRequest bundleRequest);
Task CreateJobsForBundleRequestAsync(BundleBacktestRequest bundleRequest);
IEnumerable<BundleBacktestRequest> GetBundleBacktestRequestsByUser(User user); IEnumerable<BundleBacktestRequest> GetBundleBacktestRequestsByUser(User user);
Task<IEnumerable<BundleBacktestRequest>> GetBundleBacktestRequestsByUserAsync(User user); Task<IEnumerable<BundleBacktestRequest>> GetBundleBacktestRequestsByUserAsync(User user);
BundleBacktestRequest? GetBundleBacktestRequestByIdForUser(User user, Guid id); BundleBacktestRequest? GetBundleBacktestRequestByIdForUser(User user, Guid id);

View File

@@ -108,6 +108,8 @@ public class BacktestExecutorAdapter : IBacktester
public Task<bool> DeleteBacktestsByRequestIdAsync(Guid requestId) => throw new NotImplementedException("Not available in compute worker"); public Task<bool> DeleteBacktestsByRequestIdAsync(Guid requestId) => throw new NotImplementedException("Not available in compute worker");
public Task<int> DeleteBacktestsByFiltersAsync(User user, BacktestsFilter filter) => throw new NotImplementedException("Not available in compute worker"); public Task<int> 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 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<BundleBacktestRequest> GetBundleBacktestRequestsByUser(User user) => throw new NotImplementedException("Not available in compute worker"); public IEnumerable<BundleBacktestRequest> GetBundleBacktestRequestsByUser(User user) => throw new NotImplementedException("Not available in compute worker");
public Task<IEnumerable<BundleBacktestRequest>> GetBundleBacktestRequestsByUserAsync(User user) => throw new NotImplementedException("Not available in compute worker"); public Task<IEnumerable<BundleBacktestRequest>> 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"); public BundleBacktestRequest? GetBundleBacktestRequestByIdForUser(User user, Guid id) => throw new NotImplementedException("Not available in compute worker");

View File

@@ -397,6 +397,51 @@ namespace Managing.Application.Backtests
} }
} }
/// <summary>
/// Saves a bundle backtest request without creating jobs.
/// Use this when you want to return immediately and create jobs in a background task.
/// </summary>
public async Task SaveBundleBacktestRequestAsync(User user, BundleBacktestRequest bundleRequest)
{
await _backtestRepository.InsertBundleBacktestRequestForUserAsync(user, bundleRequest);
}
/// <summary>
/// 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.
/// </summary>
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;
}
}
/// <summary> /// <summary>
/// Generates individual backtest requests from variant configuration /// Generates individual backtest requests from variant configuration
/// </summary> /// </summary>

View File

@@ -122,6 +122,7 @@ public class BacktestComputeWorker : BackgroundService
var executor = scope.ServiceProvider.GetRequiredService<BacktestExecutor>(); var executor = scope.ServiceProvider.GetRequiredService<BacktestExecutor>();
var userService = scope.ServiceProvider.GetRequiredService<IUserService>(); var userService = scope.ServiceProvider.GetRequiredService<IUserService>();
var exchangeService = scope.ServiceProvider.GetRequiredService<IExchangeService>(); var exchangeService = scope.ServiceProvider.GetRequiredService<IExchangeService>();
var agentSummaryRepository = scope.ServiceProvider.GetRequiredService<IAgentSummaryRepository>();
try try
{ {
@@ -192,6 +193,18 @@ public class BacktestComputeWorker : BackgroundService
await jobRepository.UpdateAsync(job); 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( _logger.LogInformation(
"Completed backtest job {JobId}. Score: {Score}, PnL: {PnL}", "Completed backtest job {JobId}. Score: {Score}, PnL: {PnL}",
job.Id, result.Score, result.FinalPnl); job.Id, result.Score, result.FinalPnl);