修复学业预警的按时定时任务

This commit is contained in:
2026-08-11 08:57:43 +08:00 Unverified
parent d22c4d6de9
commit 9b32ee916c
@@ -7,6 +7,8 @@ namespace Jiaowu.Api.Infrastructure.Scheduling;
public sealed class WarningCheckWorker(IServiceScopeFactory scopeFactory, ILogger<WarningCheckWorker> logger) : BackgroundService public sealed class WarningCheckWorker(IServiceScopeFactory scopeFactory, ILogger<WarningCheckWorker> logger) : BackgroundService
{ {
private static readonly TimeZoneInfo ChinaTimeZone = ResolveChinaTimeZone();
protected override async Task ExecuteAsync(CancellationToken ct) protected override async Task ExecuteAsync(CancellationToken ct)
{ {
while (!ct.IsCancellationRequested) while (!ct.IsCancellationRequested)
@@ -25,22 +27,32 @@ public sealed class WarningCheckWorker(IServiceScopeFactory scopeFactory, ILogge
private static async Task RunAsync(AppDbContext db, CancellationToken ct) private static async Task RunAsync(AppDbContext db, CancellationToken ct)
{ {
var now = DateTime.UtcNow; var nowUtc = DateTime.UtcNow;
var dow = (int)now.DayOfWeek == 0 ? 7 : (int)now.DayOfWeek; var chinaNow = TimeZoneInfo.ConvertTime(
var currentMinute = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc); new DateTimeOffset(nowUtc),
ChinaTimeZone);
var dow = (int)chinaNow.DayOfWeek == 0 ? 7 : (int)chinaNow.DayOfWeek;
var currentMinuteUtc = new DateTime(
nowUtc.Year,
nowUtc.Month,
nowUtc.Day,
nowUtc.Hour,
nowUtc.Minute,
0,
DateTimeKind.Utc);
var rules = await db.WarningRules var rules = await db.WarningRules
.Where(r => r.IsEnabled && r.AutoCheckEnabled && .Where(r => r.IsEnabled && r.AutoCheckEnabled &&
r.CheckHour == now.Hour && r.CheckMinute == now.Minute && r.CheckHour == chinaNow.Hour && r.CheckMinute == chinaNow.Minute &&
(r.CheckDayOfWeek == null || r.CheckDayOfWeek == dow)) (r.CheckDayOfWeek == null || r.CheckDayOfWeek == dow))
.ToListAsync(ct); .ToListAsync(ct);
foreach (var rule in rules) foreach (var rule in rules)
{ {
if (rule.LastCheckAt.HasValue && rule.LastCheckAt.Value >= currentMinute) if (rule.LastCheckAt.HasValue && rule.LastCheckAt.Value >= currentMinuteUtc)
continue; continue;
rule.LastCheckAt = now; rule.LastCheckAt = nowUtc;
await db.SaveChangesAsync(ct); await db.SaveChangesAsync(ct);
var studentIds = await db.Students.Where(x => x.Status == StudentStatus.Active).Select(x => x.Id).ToListAsync(ct); var studentIds = await db.Students.Where(x => x.Status == StudentStatus.Active).Select(x => x.Id).ToListAsync(ct);
@@ -100,4 +112,23 @@ public sealed class WarningCheckWorker(IServiceScopeFactory scopeFactory, ILogge
var gpa = grades.Average(x => x.GradePoint!.Value); var gpa = grades.Average(x => x.GradePoint!.Value);
return gpa < rule.Threshold ? new WarningRecord { StudentId = sid, Type = WarningType.LowGPA, TriggerValue = Math.Round(gpa, 2), Detail = $"平均绩点 {gpa:F2},低于预警阈值 {rule.Threshold}。", AcademicTermId = termId } : null; return gpa < rule.Threshold ? new WarningRecord { StudentId = sid, Type = WarningType.LowGPA, TriggerValue = Math.Round(gpa, 2), Detail = $"平均绩点 {gpa:F2},低于预警阈值 {rule.Threshold}。", AcademicTermId = termId } : null;
} }
private static TimeZoneInfo ResolveChinaTimeZone()
{
foreach (var id in new[] { "Asia/Shanghai", "China Standard Time" })
{
try
{
return TimeZoneInfo.FindSystemTimeZoneById(id);
}
catch (TimeZoneNotFoundException)
{
}
catch (InvalidTimeZoneException)
{
}
}
throw new InvalidOperationException("服务器未提供中国标准时间时区定义。");
}
} }