using FreeRedis; using SJZY.Expand.ABP.Core; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Dtos.Forewarning; using SJZY.Track.Domain.Enums; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.ForewarningServices; /// /// 用于处理预警通知 /// public class ForewarningNotifyService : IForewarningNotifyService, ITransientDependency { private IRuleFactorCacheService _ruleFactorCache; IReadOnlyDictionary> _ruleGroupDict; IReadOnlyDictionary> _factorDict; private IReadOnlyDictionary _rules; readonly INotifyService _notifyService; public ForewarningNotifyService(IRuleFactorCacheService ruleFactorCache, INotifyService notifyService) { _ruleFactorCache = ruleFactorCache; _notifyService = notifyService; } /// /// 创建预警通知 /// /// 创建预警通知需要的订单信息 /// 创建的通知总量,0表示没有规则 public async Task CreateForewarningNotify(ForewarningOrderModel order) { var rules = GetRule(order); if (rules == null || rules.Count == 0) return 0; return await ExecuteRule(rules, order.Id); } /// /// 清除预警通知 /// /// 订单信息 /// 清理的行数 public async Task DeleteForewarningNotify(ForewarningOrderModel order) { var rules = GetRule(order); if (rules == null || rules.Count == 0) return 0; var willDeleteMembers = new List(); foreach (var rule in rules) { var allRuleNotities = DeleteNotifyValue(rule, order.Id); willDeleteMembers.AddRange(allRuleNotities); } await RedisHelper.Client.ZRemAsync(GlobalConst.ForewarningNotifyKeyPrefix, willDeleteMembers.ToArray()); return willDeleteMembers.Count; } public void SendNotification(int intervalMinute) { var currentTimestamp = GetTimestamp(DateTime.Now); var notifyMembers = RedisHelper.Client.ZRangeByScore(GlobalConst.ForewarningNotifyKeyPrefix, 0, currentTimestamp); if (notifyMembers == null || notifyMembers.Length == 0) return; var notifyValues = notifyMembers.Select(val => new RuleNotifyValue(val)); foreach (var notifyValue in notifyValues) { if (!_rules.TryGetValue(notifyValue.RuleId, out var rule)) continue; //todo 发送通知 _notifyService.SendNotification(""); } } public void ClearCache() { _ruleGroupDict = null; _factorDict = null; _rules = null; } private List DeleteNotifyValue(ForewarningRuleItem ruleItem, int orderId) { var members = new List(); for (var index = 0; index < ruleItem.Count; index++) { var notifyValue = NotifyValue(ruleItem, orderId, index); members.Add(notifyValue); } return members; } /// /// 获取规则 /// /// /// private List GetRule(ForewarningOrderModel order) { if (!_factorDict.TryGetValue(GetFactorKey(order.CustomerId, order.SystemId), out var factors)) { return null; } var keys = GetForewarningKeys(factors, order); var result = new List(); foreach (var item in keys) { if (!_ruleGroupDict.TryGetValue(item, out var rules)) continue; var allRules = rules.Where(val => val.TrackStart <= order.Track && val.TrackEnd >= order.Track); result.AddRange(allRules); } return result; } private async ValueTask ExecuteRule(List rules, int orderId) { var members = new List(); foreach (var rule in rules) { var notifys = ExecuteRule(rule, orderId); members.AddRange(notifys); } await RedisHelper.Client.ZAddAsync(GlobalConst.ForewarningNotifyKeyPrefix, members.ToArray()); return members.Count; } private List ExecuteRule(ForewarningRuleItem ruleItem, int orderId) { var members = new List(); var intervalMinute = 60 * ((ruleItem.Timeliness - ruleItem.Remind) / ruleItem.Count); // 间隔多少分钟 for (var index = 0; index < ruleItem.Count; index++) { var notifyTime = (ruleItem.Remind * 60) + intervalMinute * index; var notifyTimestamp = GetTimestamp(DateTime.Now.AddMinutes(notifyTime)); var notifyValue = new ZMember(NotifyValue(ruleItem, orderId, index), notifyTimestamp); members.Add(notifyValue); } return members; } private long GetTimestamp(DateTime dateTime) { return new DateTimeOffset(dateTime).ToUnixTimeSeconds(); } private string NotifyValue(ForewarningRuleItem ruleItem, int orderId, int sort) { var result = new RuleNotifyValue(ruleItem.Id, orderId, sort, ruleItem.TrackEnd); return result.ToString(); } private List GetForewarningKeys(List factors, IForewarningFactorValue rule) { var keys = new List(); foreach (var factor in factors) { var key = GetRuleKey(rule, factor); keys.Add(key); } return keys; } private async Task Init() { // todo:缓存设计有问题 重构 120s 10w 30w 3000k/s var allFactorCollect = await _ruleFactorCache.GetAllFactorCollect(); var factors = await _ruleFactorCache.GetAllRuleFactor(); var factorsMap = factors.GroupBy(val => val.RuleId) .ToDictionary(val => val.Key, val => val.First()); _rules = allFactorCollect.ToDictionary(val => val.Id); _factorDict = factors.GroupBy(val => GetFactorKey(val.CustomerId, val.SystemId)) .ToDictionary(val => val.Key, val => val.ToList()); _ruleGroupDict = allFactorCollect.GroupBy(x => GetRuleKey(x, factorsMap[x.RuleId])) .ToDictionary(val => val.Key, val => val.ToList()); } private string GetFactorKey(int customerId, int systemId) { return $"{customerId}:{systemId}"; } private string GetRuleKey(IForewarningFactorValue rule, RuleFactor factors) { var key = ""; foreach (var factorItem in factors.FactorItems) { key += GetFactorValue(factorItem, rule); } return key; } private string GetFactorValue(FactorItemModel factorItem, IForewarningFactorValue rule) { switch (factorItem.FactorType) { case RuleFactorType.Areas: return rule.Area.HasValue ? rule.Area.Value.ToString() : throw new Exception("区域不能为空"); case RuleFactorType.CargoType: return rule.CargoType; case RuleFactorType.LeavePort: return rule.LeavePort; case RuleFactorType.Months: return rule.Month.HasValue ? rule.Month.Value.ToString() : throw new Exception("月份不能为空"); case RuleFactorType.ProductCode: return rule.ProductCode; case RuleFactorType.IsTransit: return rule.IsTransit.HasValue ? "1" : "0"; // Add additional cases for other RuleFactorTypes as needed default: throw new Exception("未知的规则类型"); } } }