147 lines
6.5 KiB
C#
147 lines
6.5 KiB
C#
using FreeSql;
|
||
|
||
using LiveForum.Code.Redis.Contract;
|
||
using LiveForum.IService.Others;
|
||
using LiveForum.Model;
|
||
|
||
using Microsoft.Extensions.Logging;
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace LiveForum.Service.ScheduledJobs
|
||
{
|
||
/// <summary>
|
||
/// 主播送花数量重置任务
|
||
/// 每月1号凌晨3点执行,清空所有主播的送花数量,然后从T_FlowerRecords表重新统计当月数据
|
||
/// </summary>
|
||
public class StreamerFlowerResetJob : IScheduledJobService
|
||
{
|
||
private readonly IBaseRepository<T_Streamers> _streamersRepository;
|
||
private readonly IBaseRepository<T_FlowerRecords> _flowerRecordsRepository;
|
||
private readonly IRedisService _redisService;
|
||
private readonly ILogger<StreamerFlowerResetJob> _logger;
|
||
private const int BatchSize = 500; // 每批处理500条记录
|
||
private const string FLOWER_COUNT_KEY_PREFIX = "flower_count:";
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
/// <param name="streamersRepository">主播仓储</param>
|
||
/// <param name="flowerRecordsRepository">送花记录仓储</param>
|
||
/// <param name="redisService">Redis服务</param>
|
||
/// <param name="logger">日志记录器</param>
|
||
public StreamerFlowerResetJob(
|
||
IBaseRepository<T_Streamers> streamersRepository,
|
||
IBaseRepository<T_FlowerRecords> flowerRecordsRepository,
|
||
IRedisService redisService,
|
||
ILogger<StreamerFlowerResetJob> logger)
|
||
{
|
||
_streamersRepository = streamersRepository;
|
||
_flowerRecordsRepository = flowerRecordsRepository;
|
||
_redisService = redisService;
|
||
_logger = logger;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置主播送花数量(每月清零并重新统计当月数据)
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public async Task ResetStreamerFlowerCountAsync()
|
||
{
|
||
var startTime = DateTime.Now;
|
||
_logger.LogInformation("[定时任务] 开始执行主播送花数量重置任务,开始时间:{StartTime}", startTime);
|
||
|
||
try
|
||
{
|
||
// 1. 获取当前月份(yyyy-MM格式)
|
||
var currentMonth = DateTime.Now.ToString("yyyy-MM");
|
||
_logger.LogInformation("[定时任务] 当前月份:{CurrentMonth}", currentMonth);
|
||
|
||
// 2. 将所有主播的FlowerCount清零(批量更新)
|
||
_logger.LogInformation("[定时任务] 开始将所有主播的送花数量清零...");
|
||
var resetCount = await _streamersRepository.UpdateDiy
|
||
.Set(x => x.FlowerCount == 0)
|
||
.ExecuteAffrowsAsync();
|
||
_logger.LogInformation("[定时任务] 已清零 {ResetCount} 个主播的送花数量", resetCount);
|
||
|
||
// 2.5 清除Redis中所有主播的花数缓存
|
||
_logger.LogInformation("[定时任务] 开始清除Redis花数缓存...");
|
||
var allStreamers = await _streamersRepository.Select.ToListAsync();
|
||
var clearedCount = 0;
|
||
foreach (var streamer in allStreamers)
|
||
{
|
||
var cacheKey = $"{FLOWER_COUNT_KEY_PREFIX}Streamer:{streamer.Id}";
|
||
await _redisService.RemoveAsync(cacheKey);
|
||
clearedCount++;
|
||
}
|
||
_logger.LogInformation("[定时任务] 已清除 {ClearedCount} 个主播的Redis花数缓存", clearedCount);
|
||
|
||
// 3. 从T_FlowerRecords表统计当月数据
|
||
_logger.LogInformation("[定时任务] 开始统计当月送花记录...");
|
||
// 先查询所有符合条件的记录
|
||
var flowerRecords = await _flowerRecordsRepository.Select
|
||
.Where(x => x.SendMonth == currentMonth && x.TargetType == "Streamer")
|
||
.ToListAsync();
|
||
|
||
// 在内存中分组并统计
|
||
var monthlyStats = flowerRecords
|
||
.GroupBy(x => x.TargetId)
|
||
.Select(g => new
|
||
{
|
||
TargetId = g.Key,
|
||
TotalFlowers = g.Sum(x => x.FlowerCount)
|
||
})
|
||
.ToList();
|
||
_logger.LogInformation("[定时任务] 统计完成,共有 {Count} 个主播有当月送花记录", monthlyStats.Count);
|
||
|
||
if (!monthlyStats.Any())
|
||
{
|
||
_logger.LogInformation("[定时任务] 当月没有送花记录,任务完成");
|
||
return;
|
||
}
|
||
|
||
// 4. 分批更新主播的FlowerCount
|
||
var totalCount = monthlyStats.Count;
|
||
var processedCount = 0;
|
||
var batchNumber = 0;
|
||
|
||
while (processedCount < totalCount)
|
||
{
|
||
batchNumber++;
|
||
var batch = monthlyStats.Skip(processedCount).Take(BatchSize).ToList();
|
||
var batchSize = batch.Count;
|
||
|
||
_logger.LogInformation("[定时任务] 开始处理第 {BatchNumber} 批,本批 {BatchSize} 条记录", batchNumber, batchSize);
|
||
|
||
// 批量更新本批主播的送花数量
|
||
foreach (var stat in batch)
|
||
{
|
||
await _streamersRepository.UpdateDiy
|
||
.Set(x => x.FlowerCount == stat.TotalFlowers)
|
||
.Where(x => x.Id == stat.TargetId)
|
||
.ExecuteAffrowsAsync();
|
||
}
|
||
|
||
processedCount += batchSize;
|
||
_logger.LogInformation("[定时任务] 第 {BatchNumber} 批处理完成,已处理 {ProcessedCount}/{TotalCount} 条记录",
|
||
batchNumber, processedCount, totalCount);
|
||
}
|
||
|
||
var endTime = DateTime.Now;
|
||
var duration = endTime - startTime;
|
||
_logger.LogInformation("[定时任务] 主播送花数量重置任务执行完成!总耗时:{Duration}秒,共处理 {TotalCount} 个主播",
|
||
duration.TotalSeconds, totalCount);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "[定时任务] 主播送花数量重置任务执行失败!");
|
||
throw; // 重新抛出异常,让Hangfire记录失败状态
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|