88 lines
3.0 KiB
C#
88 lines
3.0 KiB
C#
using Microsoft.EntityFrameworkCore;
|
||
using MilliSim.Common.Models;
|
||
using MilliSim.Data;
|
||
|
||
namespace MilliSim.Services;
|
||
|
||
/// <summary>
|
||
/// 后台定时任务:每天检查即将到期(7 天内)的授权,给被授权用户发送提醒通知。
|
||
/// 使用 EventId = "auth-expiring-{authId}-{expiryDate}" 进行幂等,避免重复发送。
|
||
/// </summary>
|
||
public class AuthorizationNotificationJob : IHostedService, IDisposable
|
||
{
|
||
private readonly IServiceProvider _serviceProvider;
|
||
private Timer? _timer;
|
||
|
||
// 检查间隔:6 小时(既能在到期日及时触发,又避免频繁扫描)
|
||
private static readonly TimeSpan CheckInterval = TimeSpan.FromHours(6);
|
||
// 提前提醒天数
|
||
private const int ExpiringSoonDays = 7;
|
||
|
||
public AuthorizationNotificationJob(IServiceProvider serviceProvider)
|
||
{
|
||
_serviceProvider = serviceProvider;
|
||
}
|
||
|
||
public Task StartAsync(CancellationToken cancellationToken)
|
||
{
|
||
// 启动后 30 秒执行第一次,之后每 6 小时一次
|
||
_timer = new Timer(DoWork, null, TimeSpan.FromSeconds(30), CheckInterval);
|
||
return Task.CompletedTask;
|
||
}
|
||
|
||
public Task StopAsync(CancellationToken cancellationToken)
|
||
{
|
||
_timer?.Change(Timeout.Infinite, 0);
|
||
return Task.CompletedTask;
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
_timer?.Dispose();
|
||
}
|
||
|
||
private async void DoWork(object? state)
|
||
{
|
||
try
|
||
{
|
||
using var scope = _serviceProvider.CreateScope();
|
||
var db = scope.ServiceProvider.GetRequiredService<MilliSimDbContext>();
|
||
var notification = scope.ServiceProvider.GetRequiredService<INotificationService>();
|
||
|
||
var now = DateTime.Now;
|
||
var deadline = now.AddDays(ExpiringSoonDays);
|
||
|
||
// 查询 7 天内即将到期、且尚未过期的有效授权
|
||
var expiringSoon = await db.Authorizations
|
||
.Where(a => a.Status == AuthorizationStatus.Active
|
||
&& a.EndTime > now
|
||
&& a.EndTime <= deadline)
|
||
.ToListAsync();
|
||
|
||
foreach (var auth in expiringSoon)
|
||
{
|
||
var daysRemaining = Math.Max(1, (int)Math.Ceiling((auth.EndTime - now).TotalDays));
|
||
// 按到期日期去重:同一天内只发一次
|
||
var eventId = $"auth-expiring-{auth.Id}-{auth.EndTime:yyyyMMdd}";
|
||
try
|
||
{
|
||
await notification.CreateNotificationAsync(
|
||
NotificationType.Authorization,
|
||
"授权即将到期",
|
||
$"您的客户级授权将在 {daysRemaining} 天后到期({auth.EndTime:yyyy-MM-dd}),请及时联系销售续期。",
|
||
userId: auth.UserId,
|
||
eventId: eventId);
|
||
}
|
||
catch
|
||
{
|
||
// 单条失败不影响其他通知
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 后台任务异常不应影响应用运行
|
||
}
|
||
}
|
||
}
|