refactor(dotnet): standardize scheduler state and definitions
This commit is contained in:
@@ -73,6 +73,20 @@ public class SchedulerServiceTests
|
|||||||
), Times.Once);
|
), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetRecurringJobDefinitions_ReturnsCanonicalDefinitions()
|
||||||
|
{
|
||||||
|
var service = CreateService();
|
||||||
|
|
||||||
|
var defs = service.GetRecurringJobDefinitions();
|
||||||
|
|
||||||
|
Assert.Equal(4, defs.Count);
|
||||||
|
Assert.Contains(defs, d => d.JobId == "daily-collection" && d.IsRecurring);
|
||||||
|
Assert.Contains(defs, d => d.JobId == "hourly-price-update" && d.IsRecurring);
|
||||||
|
Assert.Contains(defs, d => d.JobId == "weekly-report" && d.IsRecurring);
|
||||||
|
Assert.Contains(defs, d => d.JobId == "monthly-optimization" && d.IsRecurring);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void LoadTickersFromJson_WhenFileMissing_FallsBackToDefaultUniverse()
|
public void LoadTickersFromJson_WhenFileMissing_FallsBackToDefaultUniverse()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
namespace QuantEngine.Web.Services;
|
||||||
|
|
||||||
|
public sealed record SchedulerJobDefinition(
|
||||||
|
string JobId,
|
||||||
|
string Cron,
|
||||||
|
string Description,
|
||||||
|
bool IsRecurring);
|
||||||
|
|
||||||
|
public sealed record SchedulerJobExecutionAudit(
|
||||||
|
string JobId,
|
||||||
|
string RunId,
|
||||||
|
string State,
|
||||||
|
string? Reason,
|
||||||
|
DateTimeOffset StartedAt,
|
||||||
|
DateTimeOffset? FinishedAt,
|
||||||
|
string? ResourceKey);
|
||||||
|
|
||||||
|
public static class SchedulerStates
|
||||||
|
{
|
||||||
|
public const string Pending = "PENDING";
|
||||||
|
public const string Running = "RUNNING";
|
||||||
|
public const string Succeeded = "SUCCEEDED";
|
||||||
|
public const string Failed = "FAILED";
|
||||||
|
public const string Retrying = "RETRYING";
|
||||||
|
public const string Blocked = "BLOCKED";
|
||||||
|
}
|
||||||
@@ -16,12 +16,6 @@ namespace QuantEngine.Web.Services;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SchedulerService
|
public class SchedulerService
|
||||||
{
|
{
|
||||||
private sealed record RecurringJobDefinition(
|
|
||||||
string JobId,
|
|
||||||
Expression<Func<Task>> Job,
|
|
||||||
string Cron,
|
|
||||||
string Description);
|
|
||||||
|
|
||||||
private readonly ILogger<SchedulerService> _logger;
|
private readonly ILogger<SchedulerService> _logger;
|
||||||
private readonly IBackgroundJobClient _jobClient;
|
private readonly IBackgroundJobClient _jobClient;
|
||||||
private readonly IRecurringJobManager _recurringJobManager;
|
private readonly IRecurringJobManager _recurringJobManager;
|
||||||
@@ -82,12 +76,12 @@ public class SchedulerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReadOnlyList<RecurringJobDefinition> BuildRecurringJobs() => new[]
|
public IReadOnlyList<SchedulerJobDefinition> GetRecurringJobDefinitions() => new[]
|
||||||
{
|
{
|
||||||
new RecurringJobDefinition("daily-collection", () => RunDailyCollectionAsync(), "0 9 * * *", "Daily data collection"),
|
new SchedulerJobDefinition("daily-collection", "0 9 * * *", "Daily data collection", true),
|
||||||
new RecurringJobDefinition("hourly-price-update", () => UpdatePricesAsync(), "0 9,11,13,15 * * 1-5", "Hourly price update"),
|
new SchedulerJobDefinition("hourly-price-update", "0 9,11,13,15 * * 1-5", "Hourly price update", true),
|
||||||
new RecurringJobDefinition("weekly-report", () => GenerateWeeklyReportAsync(), "0 17 * * 5", "Weekly report generation"),
|
new SchedulerJobDefinition("weekly-report", "0 17 * * 5", "Weekly report generation", true),
|
||||||
new RecurringJobDefinition("monthly-optimization", () => RunMonthlyOptimizationAsync(), "0 2 1 * *", "Monthly optimization"),
|
new SchedulerJobDefinition("monthly-optimization", "0 2 1 * *", "Monthly optimization", true),
|
||||||
};
|
};
|
||||||
|
|
||||||
private static string? FindGatherTradingDataJson()
|
private static string? FindGatherTradingDataJson()
|
||||||
@@ -118,11 +112,11 @@ public class SchedulerService
|
|||||||
{
|
{
|
||||||
_logger.LogInformation("Initializing Hangfire schedules...");
|
_logger.LogInformation("Initializing Hangfire schedules...");
|
||||||
|
|
||||||
foreach (var job in BuildRecurringJobs())
|
foreach (var job in GetRecurringJobDefinitions())
|
||||||
{
|
{
|
||||||
_recurringJobManager.AddOrUpdate(
|
_recurringJobManager.AddOrUpdate(
|
||||||
job.JobId,
|
job.JobId,
|
||||||
job.Job,
|
ResolveRecurringJob(job.JobId),
|
||||||
job.Cron,
|
job.Cron,
|
||||||
new RecurringJobOptions { TimeZone = TimeZoneInfo.Local }
|
new RecurringJobOptions { TimeZone = TimeZoneInfo.Local }
|
||||||
);
|
);
|
||||||
@@ -279,6 +273,15 @@ public class SchedulerService
|
|||||||
return JobStorage.Current.GetConnection().GetJobData(jobId)?.State;
|
return JobStorage.Current.GetConnection().GetJobData(jobId)?.State;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Expression<Func<Task>> ResolveRecurringJob(string jobId) => jobId switch
|
||||||
|
{
|
||||||
|
"daily-collection" => () => RunDailyCollectionAsync(),
|
||||||
|
"hourly-price-update" => () => UpdatePricesAsync(),
|
||||||
|
"weekly-report" => () => GenerateWeeklyReportAsync(),
|
||||||
|
"monthly-optimization" => () => RunMonthlyOptimizationAsync(),
|
||||||
|
_ => throw new InvalidOperationException($"Unknown recurring job id: {jobId}")
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cancel scheduled job
|
/// Cancel scheduled job
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user