track/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs

236 lines
7.8 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 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;
/// <summary>
/// 用于处理预警通知
/// </summary>
public class ForewarningNotifyService : IForewarningNotifyService, ITransientDependency
{
private IRuleFactorCacheService _ruleFactorCache;
IReadOnlyDictionary<string, List<ForewarningRuleItem>> _ruleGroupDict;
IReadOnlyDictionary<string, List<RuleFactor>> _factorDict;
private IReadOnlyDictionary<int, ForewarningRuleItem> _rules;
readonly INotifyService _notifyService;
public ForewarningNotifyService(IRuleFactorCacheService ruleFactorCache, INotifyService notifyService)
{
_ruleFactorCache = ruleFactorCache;
_notifyService = notifyService;
}
/// <summary>
/// 创建预警通知
/// </summary>
/// <param name="order">创建预警通知需要的订单信息</param>
/// <returns>创建的通知总量,0表示没有规则</returns>
public async Task<int> CreateForewarningNotify(ForewarningOrderModel order)
{
var rules = GetRule(order);
if (rules == null || rules.Count == 0)
return 0;
return await ExecuteRule(rules, order.Id);
}
/// <summary>
/// 清除预警通知
/// </summary>
/// <param name="order">订单信息</param>
/// <returns>清理的行数</returns>
public async Task<int> DeleteForewarningNotify(ForewarningOrderModel order)
{
var rules = GetRule(order);
if (rules == null || rules.Count == 0)
return 0;
var willDeleteMembers = new List<string>();
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<string> DeleteNotifyValue(ForewarningRuleItem ruleItem, int orderId)
{
var members = new List<string>();
for (var index = 0; index < ruleItem.Count; index++)
{
var notifyValue = NotifyValue(ruleItem, orderId, index);
members.Add(notifyValue);
}
return members;
}
/// <summary>
/// 获取规则
/// </summary>
/// <param name="rule"></param>
/// <returns></returns>
private List<ForewarningRuleItem> 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<ForewarningRuleItem>();
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<int> ExecuteRule(List<ForewarningRuleItem> rules, int orderId)
{
var members = new List<ZMember>();
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<ZMember> ExecuteRule(ForewarningRuleItem ruleItem, int orderId)
{
var members = new List<ZMember>();
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<string> GetForewarningKeys(List<RuleFactor> factors, IForewarningFactorValue rule)
{
var keys = new List<string>();
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("未知的规则类型");
}
}
}