using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using NPP.SmartSchedue.Api.Contracts.Core.Repositories;
using NPP.SmartSchedue.Api.Contracts.Domain.Notification;
using NPP.SmartSchedue.Api.Contracts.Core.Enums;
using NPP.SmartSchedue.Api.Core.Repositories;
using ZhonTai.Admin.Core.Db.Transaction;
namespace NPP.SmartSchedue.Api.Repositories.Notification;
///
/// 通知任务仓储实现
/// 决策点6:定时任务,支持定时检查和触发通知
/// 业务思考:
/// 1. 支持一次性任务和周期性任务(Cron表达式)
/// 2. 任务状态管理(待执行、执行中、已完成、失败、取消)
/// 3. 任务重试机制和失效时间控制
/// 4. 任务执行结果记录和错误处理
///
public class NotificationTaskRepository : AppRepositoryBase, INotificationTaskRepository
{
public NotificationTaskRepository(UnitOfWorkManagerCloud uowm) : base(uowm)
{
}
///
/// 根据通知设置ID获取任务列表
///
public async Task> GetByNotificationSettingIdAsync(long notificationSettingId)
{
return await Select
.Where(t => t.NotificationSettingId == notificationSettingId)
.Include(t => t.NotificationSetting)
.OrderByDescending(t => t.CreatedTime)
.ToListAsync();
}
///
/// 根据任务状态获取任务列表
///
public async Task> GetByTaskStatusAsync(NotificationStatusEnum taskStatus)
{
return await Select
.Where(t => t.TaskStatus == (int)taskStatus)
.Include(t => t.NotificationSetting)
.OrderByDescending(t => t.CreatedTime)
.ToListAsync();
}
///
/// 根据启用状态获取任务列表
///
public async Task> GetByEnabledAsync(bool enabled)
{
return await Select
.Where(t => t.IsEnabled == enabled)
.Include(t => t.NotificationSetting)
.OrderByDescending(t => t.CreatedTime)
.ToListAsync();
}
///
/// 根据业务类型和业务ID获取任务列表
///
public async Task> GetByBusinessAsync(string businessType, long? businessId = null)
{
var query = Select.Where(t => t.BusinessType == businessType);
if (businessId.HasValue)
query = query.Where(t => t.BusinessId == businessId.Value);
return await query
.Include(t => t.NotificationSetting)
.OrderByDescending(t => t.CreatedTime)
.ToListAsync();
}
///
/// 获取待执行的任务列表
/// 业务逻辑:查询计划执行时间已到达且任务状态为待执行的任务
///
public async Task> GetPendingTasksAsync(DateTime currentTime)
{
return await Select
.Where(t => t.IsEnabled == true)
.Where(t => t.TaskStatus == (int)NotificationStatusEnum.Pending)
.Where(t => t.PlannedExecutionTime <= currentTime)
.Where(t => t.ExpirationTime == null || t.ExpirationTime > currentTime) // 排除已过期的任务
.Include(t => t.NotificationSetting)
.OrderBy(t => t.PlannedExecutionTime) // 按计划时间升序排序
.ToListAsync();
}
///
/// 获取需要执行的定时任务列表(基于Cron表达式)
/// 业务逻辑:
/// 1. 查询启用的周期性任务
/// 2. 检查下次执行时间是否已到达
/// 3. 验证任务未过期且未达到最大执行次数
///
public async Task> GetCronTasksForExecutionAsync(DateTime currentTime)
{
return await Select
.Where(t => t.IsEnabled == true)
.Where(t => !string.IsNullOrWhiteSpace(t.CronExpression)) // 有Cron表达式的周期性任务
.Where(t => t.TaskStatus != (int)NotificationStatusEnum.Cancelled)
.Where(t => t.NextExecutionTime <= currentTime) // 下次执行时间已到
.Where(t => t.ExpirationTime == null || t.ExpirationTime > currentTime) // 未过期
.Where(t => t.MaxExecutionCount == null || t.ExecutionCount < t.MaxExecutionCount) // 未达到最大执行次数
.Include(t => t.NotificationSetting)
.OrderBy(t => t.NextExecutionTime)
.ToListAsync();
}
///
/// 更新任务执行状态
/// 业务逻辑:更新任务状态、执行结果、错误信息等
///
public async Task UpdateExecutionStatusAsync(long taskId, NotificationStatusEnum taskStatus, string executionResult = "", string errorMessage = "")
{
var currentTime = DateTime.Now;
await UpdateDiy
.Set(t => t.TaskStatus, (int)taskStatus)
.Set(t => t.LastExecutionTime, currentTime)
.SetIf(!string.IsNullOrWhiteSpace(executionResult), t => t.ExecutionResult, executionResult)
.SetIf(!string.IsNullOrWhiteSpace(errorMessage), t => t.ErrorMessage, errorMessage)
.Set(t => t.ModifiedTime, currentTime)
.Where(t => t.Id == taskId)
.ExecuteAffrowsAsync();
}
///
/// 更新任务下次执行时间
/// 业务场景:周期性任务完成后,根据Cron表达式计算下次执行时间
///
public async Task UpdateNextExecutionTimeAsync(long taskId, DateTime? nextExecutionTime)
{
await UpdateDiy
.Set(t => t.NextExecutionTime, nextExecutionTime)
.Set(t => t.ModifiedTime, DateTime.Now)
.Where(t => t.Id == taskId)
.ExecuteAffrowsAsync();
}
///
/// 增加任务执行次数
/// 业务逻辑:记录任务执行统计,用于控制最大执行次数和成功率分析
///
public async Task IncrementExecutionCountAsync(long taskId, bool isSuccess)
{
var task = await Select.Where(t => t.Id == taskId).FirstAsync();
if (task == null) return;
await UpdateDiy
.Set(t => t.ExecutionCount, task.ExecutionCount + 1)
.SetIf(isSuccess, t => t.SuccessCount, task.SuccessCount + 1)
.SetIf(!isSuccess, t => t.FailureCount, task.FailureCount + 1)
.Set(t => t.ModifiedTime, DateTime.Now)
.Where(t => t.Id == taskId)
.ExecuteAffrowsAsync();
}
///
/// 检查任务是否应该停止执行
/// 业务规则:
/// 1. 任务被禁用
/// 2. 任务已取消
/// 3. 已达到最大执行次数
/// 4. 任务已过期
/// 5. 连续失败次数过多
///
public async Task ShouldStopExecutionAsync(long taskId)
{
var task = await Select.Where(t => t.Id == taskId).FirstAsync();
if (task == null) return true;
var currentTime = DateTime.Now;
// 检查基本停止条件
if (!task.IsEnabled ||
task.TaskStatus == (int)NotificationStatusEnum.Cancelled ||
(task.ExpirationTime.HasValue && task.ExpirationTime.Value <= currentTime) ||
(task.MaxExecutionCount.HasValue && task.ExecutionCount >= task.MaxExecutionCount.Value))
{
return true;
}
// 检查连续失败次数(如果设置了最大重试次数)
if (task.MaxRetryCount.HasValue && task.FailureCount >= task.MaxRetryCount.Value)
{
return true;
}
return false;
}
///
/// 获取过期的任务列表
/// 业务场景:定期清理过期任务,释放系统资源
///
public async Task> GetExpiredTasksAsync(DateTime expiredBefore)
{
return await Select
.Where(t => t.ExpirationTime <= expiredBefore)
.Where(t => t.TaskStatus != (int)NotificationStatusEnum.Cancelled) // 排除已取消的任务
.OrderBy(t => t.ExpirationTime)
.ToListAsync();
}
///
/// 清理过期的任务
/// 业务逻辑:将过期任务状态设为已取消,而不是物理删除,保留审计记录
///
public async Task CleanupExpiredTasksAsync(DateTime expiredBefore)
{
var currentTime = DateTime.Now;
var affectedRows = await UpdateDiy
.Set(t => t.TaskStatus, (int)NotificationStatusEnum.Cancelled)
.Set(t => t.ErrorMessage, "任务已过期自动取消")
.Set(t => t.ModifiedTime, currentTime)
.Where(t => t.ExpirationTime <= expiredBefore)
.Where(t => t.TaskStatus != (int)NotificationStatusEnum.Cancelled)
.ExecuteAffrowsAsync();
return (int)affectedRows;
}
///
/// 获取需要重试的失败任务列表
/// 业务场景:定时重试失败的任务,提高通知送达率
///
public async Task> GetFailedTasksForRetryAsync()
{
var currentTime = DateTime.Now;
return await Select
.Where(t => t.TaskStatus == (int)NotificationStatusEnum.Failed)
.Where(t => t.IsEnabled == true)
.Where(t => t.NextRetryTime <= currentTime) // 重试时间已到
.Where(t => t.MaxRetryCount == null || t.RetryCount < t.MaxRetryCount) // 未达到最大重试次数
.Where(t => t.ExpirationTime == null || t.ExpirationTime > currentTime) // 未过期
.Include(t => t.NotificationSetting)
.OrderBy(t => t.NextRetryTime)
.ToListAsync();
}
///
/// 更新任务重试信息
/// 业务逻辑:更新重试次数和下次重试时间
///
public async Task UpdateRetryInfoAsync(long taskId, int retryCount, DateTime? nextRetryTime)
{
await UpdateDiy
.Set(t => t.RetryCount, retryCount)
.Set(t => t.NextRetryTime, nextRetryTime)
.Set(t => t.ModifiedTime, DateTime.Now)
.Where(t => t.Id == taskId)
.ExecuteAffrowsAsync();
}
///
/// 批量更新任务状态
/// 业务场景:批量操作,提高性能
///
public async Task BatchUpdateTaskStatusAsync(List taskIds, NotificationStatusEnum status, string reason = "")
{
if (!taskIds.Any()) return 0;
var currentTime = DateTime.Now;
var affectedRows = await UpdateDiy
.Set(t => t.TaskStatus, (int)status)
.SetIf(!string.IsNullOrWhiteSpace(reason), t => t.ErrorMessage, reason)
.Set(t => t.ModifiedTime, currentTime)
.Where(t => taskIds.Contains(t.Id))
.ExecuteAffrowsAsync();
return (int)affectedRows;
}
}