Add genetic grain

This commit is contained in:
2025-09-17 17:35:53 +07:00
parent 3e5b215640
commit 900405b3de
7 changed files with 161 additions and 10 deletions

View File

@@ -0,0 +1,90 @@
using Managing.Application.Abstractions.Grains;
using Managing.Application.Abstractions.Services;
using Managing.Core;
using Managing.Domain.Accounts;
using Managing.Domain.Backtests;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Orleans.Concurrency;
namespace Managing.Application.Grains;
/// <summary>
/// Stateless worker grain for processing genetic backtest requests.
/// Uses the genetic request ID (string) as the primary key.
/// </summary>
[StatelessWorker]
public class GeneticBacktestGrain : Grain, IGeneticBacktestGrain
{
private readonly ILogger<GeneticBacktestGrain> _logger;
private readonly IServiceScopeFactory _scopeFactory;
public GeneticBacktestGrain(
ILogger<GeneticBacktestGrain> logger,
IServiceScopeFactory scopeFactory)
{
_logger = logger;
_scopeFactory = scopeFactory;
}
public async Task ProcessGeneticRequestAsync()
{
var requestId = this.GetPrimaryKeyString();
try
{
using var scope = _scopeFactory.CreateScope();
var geneticService = scope.ServiceProvider.GetRequiredService<IGeneticService>();
// Load the request by status lists and filter by ID (Pending first, then Failed for retries)
var pending = await geneticService.GetGeneticRequestsAsync(GeneticRequestStatus.Pending);
var failed = await geneticService.GetGeneticRequestsAsync(GeneticRequestStatus.Failed);
var request = pending.Concat(failed).FirstOrDefault(r => r.RequestId == requestId);
if (request == null)
{
_logger.LogWarning("[GeneticBacktestGrain] Request {RequestId} not found among pending/failed.",
requestId);
return;
}
// Mark running
request.Status = GeneticRequestStatus.Running;
await geneticService.UpdateGeneticRequestAsync(request);
request.User.Accounts = await ServiceScopeHelpers.WithScopedService<IAccountService, List<Account>>(_scopeFactory,
async accountService => (await accountService.GetAccountsByUserAsync(request.User)).ToList());
// Run GA
var result = await geneticService.RunGeneticAlgorithm(request, CancellationToken.None);
// Update final state
request.Status = GeneticRequestStatus.Completed;
request.CompletedAt = DateTime.UtcNow;
request.BestFitness = result.BestFitness;
request.BestIndividual = result.BestIndividual;
request.ProgressInfo = result.ProgressInfo;
await geneticService.UpdateGeneticRequestAsync(request);
_logger.LogInformation("[GeneticBacktestGrain] Completed request {RequestId}", requestId);
}
catch (Exception ex)
{
_logger.LogError(ex, "[GeneticBacktestGrain] Error processing request {RequestId}", requestId);
try
{
using var scope = _scopeFactory.CreateScope();
var geneticService = scope.ServiceProvider.GetRequiredService<IGeneticService>();
var running = await geneticService.GetGeneticRequestsAsync(GeneticRequestStatus.Running);
var req = running.FirstOrDefault(r => r.RequestId == requestId) ?? new GeneticRequest(requestId);
req.Status = GeneticRequestStatus.Failed;
req.ErrorMessage = ex.Message;
req.CompletedAt = DateTime.UtcNow;
await geneticService.UpdateGeneticRequestAsync(req);
}
catch
{
}
}
}
}