修复学业预警的按时定时任务
This commit is contained in:
@@ -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("服务器未提供中国标准时间时区定义。");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user