feat: Jobs infrastructure, endpoints, UI and worker prioritization
This commit is contained in:
@@ -36,20 +36,40 @@ public class TradeHistoryWorker : BackgroundService
|
||||
{
|
||||
try
|
||||
{
|
||||
IReadOnlyList<Domain.Entities.Trader> tradersToProcess;
|
||||
IReadOnlyList<Domain.Entities.Trader> tradersToProcess = new List<Domain.Entities.Trader>();
|
||||
Domain.Entities.BackgroundJob? activeJob = null;
|
||||
|
||||
using (var scope = _services.CreateScope())
|
||||
{
|
||||
var jobRepo = scope.ServiceProvider.GetRequiredService<IJobRepository>();
|
||||
activeJob = await jobRepo.GetNextPendingJobAsync(Predictalytics.Domain.Enums.JobType.HistorySync, stoppingToken);
|
||||
|
||||
var repo = scope.ServiceProvider.GetRequiredService<ITraderRepository>();
|
||||
tradersToProcess = await repo.GetTradersDueForTradeUpdateAsync(CooldownHours, TradersPerCycle, stoppingToken);
|
||||
|
||||
if (activeJob != null && activeJob.TraderId.HasValue)
|
||||
{
|
||||
var t = await repo.GetByIdAsync(activeJob.TraderId.Value, stoppingToken);
|
||||
if (t != null)
|
||||
{
|
||||
tradersToProcess = new[] { t };
|
||||
activeJob.Status = Predictalytics.Domain.Enums.JobStatus.InProgress;
|
||||
activeJob.StartedAt = DateTime.UtcNow;
|
||||
await jobRepo.UpdateAsync(activeJob, stoppingToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tradersToProcess = await repo.GetTradersDueForTradeUpdateAsync(CooldownHours, TradersPerCycle, stoppingToken);
|
||||
}
|
||||
}
|
||||
|
||||
if (tradersToProcess.Count == 0)
|
||||
{
|
||||
_logger.LogDebug("📜 No traders due for sync. Sleeping.");
|
||||
_logger.LogDebug("🔄 No traders due for sync. Sleeping.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("📜 Processing {Count} traders for trade sync (Initial/Update)", tradersToProcess.Count);
|
||||
_logger.LogInformation("🔄 Processing {Count} traders for trade sync (Initial/Update)", tradersToProcess.Count);
|
||||
}
|
||||
|
||||
var outcomeCache = new System.Collections.Concurrent.ConcurrentDictionary<string, Domain.Entities.MarketOutcome>();
|
||||
@@ -166,9 +186,32 @@ public class TradeHistoryWorker : BackgroundService
|
||||
trader.LastTradesUpdatedAt = DateTime.UtcNow;
|
||||
trader.LastPolledAt = DateTime.UtcNow;
|
||||
await traderRepo.UpdateAsync(trader, ct);
|
||||
|
||||
if (activeJob != null && activeJob.TraderId == trader.Id)
|
||||
{
|
||||
using var jobScope = _services.CreateScope();
|
||||
var updateJobRepo = jobScope.ServiceProvider.GetRequiredService<IJobRepository>();
|
||||
activeJob.Status = Predictalytics.Domain.Enums.JobStatus.Completed;
|
||||
activeJob.CompletedAt = DateTime.UtcNow;
|
||||
await updateJobRepo.UpdateAsync(activeJob, ct);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { /* App shutting down */ }
|
||||
catch (Exception ex) { _logger.LogError(ex, "Error syncing trader {TraderId}", t.Id); }
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error syncing trader {TraderId}", t.Id);
|
||||
if (activeJob != null && activeJob.TraderId == t.Id)
|
||||
{
|
||||
try {
|
||||
using var jobScope = _services.CreateScope();
|
||||
var updateJobRepo = jobScope.ServiceProvider.GetRequiredService<IJobRepository>();
|
||||
activeJob.Status = Predictalytics.Domain.Enums.JobStatus.Failed;
|
||||
activeJob.CompletedAt = DateTime.UtcNow;
|
||||
activeJob.ErrorMessage = ex.Message;
|
||||
await updateJobRepo.UpdateAsync(activeJob, CancellationToken.None);
|
||||
} catch { /* Ignore secondary errors */ }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (OperationCanceledException) { break; }
|
||||
|
||||
Reference in New Issue
Block a user