Add genetic grain
This commit is contained in:
90
src/Managing.Application/Grains/GeneticBacktestGrain.cs
Normal file
90
src/Managing.Application/Grains/GeneticBacktestGrain.cs
Normal 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
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user