live-forum/server/webapi/LiveForum/LiveForum.Service/ScheduledJobs/StreamerFlowerResetJob.cs
zpc 70c1654a96
All checks were successful
continuous-integration/drone/push Build is passing
送花数量
2026-04-01 18:04:36 +08:00

147 lines
6.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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记录失败状态
}
}
}
}