222 lines
7.4 KiB
C#
222 lines
7.4 KiB
C#
using System.Collections.Concurrent;
|
|
using SJZY.Expand.ABP.Core;
|
|
using SJZY.Expand.ABP.Core.PublicMethords;
|
|
using SJZY.Track.Domain.Aggregates.ForewarningAggregate;
|
|
using SJZY.Track.Domain.Aggregates.KPIAreaAggregate;
|
|
using SJZY.Track.Domain.Consts;
|
|
using SJZY.Track.Domain.Dtos.Forewarning;
|
|
using SJZY.Track.Domain.Queries;
|
|
using Volo.Abp.DependencyInjection;
|
|
|
|
namespace SJZY.Track.Application.Services.ForewarningServices;
|
|
|
|
public class ForewarningCacheService : IForewarningCacheService, ISingletonDependency
|
|
{
|
|
private const string GlobalWaningLockKey = "GlobalWaningLockKey_GlobalLock";
|
|
private readonly ConcurrentDictionary<int, List<AreaCacheEntry>> _areas = new();
|
|
readonly IKpiAreaRepository _kpiAreaRepository;
|
|
|
|
private readonly ConcurrentDictionary<string, List<ForewarningRuleCacheEntry>> _rules = new();
|
|
private readonly IWarningQueries _warningQueries;
|
|
object _lock = new object();
|
|
|
|
public ForewarningCacheService(IKpiAreaRepository kpiAreaRepository, IWarningQueries warningQueries)
|
|
{
|
|
_kpiAreaRepository = kpiAreaRepository;
|
|
_warningQueries = warningQueries;
|
|
}
|
|
|
|
public async Task<List<ForewarningRuleCacheEntry>?> GetRulesAsync(int subSystemId, int customerId)
|
|
{
|
|
var key = WarningKey(subSystemId, customerId);
|
|
if( _rules.TryGetValue(key,out var rules))
|
|
{
|
|
return rules;
|
|
}
|
|
|
|
return await GetRules(subSystemId, customerId);
|
|
}
|
|
|
|
public Task DeleteRulesAsync(int subSystemId, int customerId)
|
|
{
|
|
_rules.Remove(WarningKey(subSystemId, customerId),out _);
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task Clear(ClearRulCacheEvent @event)
|
|
{
|
|
foreach (var item in @event.Items)
|
|
{
|
|
DeleteRulesAsync(item.SystemId, item.CustomerId);
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public async Task ClearRedisBySystemIdAndCustomer(int subSystemId,int customerId)
|
|
{
|
|
await RedisHelper.Client.DelAsync(WarningKey(subSystemId, customerId));
|
|
var eventModel = new ClearRulCacheEvent
|
|
{
|
|
Items = new List<RuleAreaBaseInfo>()
|
|
{
|
|
new RuleAreaBaseInfo(subSystemId, customerId)
|
|
}
|
|
};
|
|
|
|
await PublishEvent(eventModel);
|
|
}
|
|
|
|
public async Task ClearRedisByAreaId(int areaId)
|
|
{
|
|
var baseInfos = await _warningQueries.GetWarningRuleByAreaId(areaId);
|
|
if(baseInfos==null||baseInfos.Count==0) return;
|
|
baseInfos = baseInfos.DistinctBy(val => WarningKey(val.SystemId, val.CustomerId)).ToList();
|
|
|
|
var willDelKeys = baseInfos.Select(val => WarningKey(val.SystemId, val.CustomerId)).ToArray();
|
|
await RedisHelper.Client.DelAsync(willDelKeys);
|
|
await RedisHelper.Client.DelAsync(AreaKey(areaId));
|
|
var eventModel = new ClearRulCacheEvent
|
|
{
|
|
Items = baseInfos
|
|
};
|
|
|
|
await PublishEvent(eventModel);
|
|
}
|
|
|
|
string WarningKey(int subSystemId, int customerId) =>
|
|
$"{GlobalConst.TrackWarningKeyPrefix}:{subSystemId}:{customerId}";
|
|
|
|
string AreaKey(int areaId) => $"{GlobalConst.TrackAreaKeyPrefix}:{areaId}";
|
|
|
|
private List<ForewarningRuleCacheEntry> WriteRules(List<WarningRuleCacheDto> rules)
|
|
{
|
|
List<ForewarningRuleCacheEntry> result = new List<ForewarningRuleCacheEntry>();
|
|
foreach (var item in rules)
|
|
{
|
|
List<AreaCacheEntry>? areaList = null;
|
|
if (item.AreaId.HasValue)
|
|
{
|
|
areaList = GetAreaInfoByAreaId(item.AreaId!.Value);
|
|
}
|
|
|
|
var entry = new ForewarningRuleCacheEntry
|
|
{
|
|
Id = item.Id,
|
|
WarningId = item.WarningId,
|
|
TotalTimeSpan = item.TotalTimeSpan,
|
|
WarnTimeSpan = item.WarnTimeSpan,
|
|
WarnCount = item.WarnCount,
|
|
StartTrackStatusId = item.StartTrackStatusId,
|
|
EndTrackStatusId = item.EndTrackStatusId,
|
|
CargoType = item.CargoType,
|
|
Months = string.IsNullOrEmpty(item.Months)
|
|
? new List<int>()
|
|
: item.Months.Split('/').Select(int.Parse).ToList(),
|
|
IsTransit = item.IsTransit,
|
|
Areas = areaList,
|
|
ProductCode = item.ProductCode,
|
|
LeavePort = item.LeavePort
|
|
};
|
|
|
|
result.Add(entry);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private async Task<List<ForewarningRuleCacheEntry>?> GetRules(int systemId, int customerId)
|
|
{
|
|
var key = WarningKey(systemId, customerId);
|
|
var result = RedisHelper.Client.Get<List<WarningRuleCacheDto>>(key);
|
|
if (result != null)
|
|
{
|
|
// 非线程安全,需要加锁
|
|
lock (_lock)
|
|
{
|
|
if (_rules.TryGetValue(key, out var ruleResult))
|
|
{
|
|
return ruleResult;
|
|
}
|
|
|
|
ruleResult = WriteRules(result);
|
|
_rules.TryAdd(key,ruleResult);
|
|
return ruleResult;
|
|
}
|
|
}
|
|
|
|
// 非线程安全,需要加锁
|
|
using (RedisHelper.Client.Lock(GlobalWaningLockKey, 20))
|
|
{
|
|
if (_rules.TryGetValue(key, out var ruleResult)) return ruleResult;
|
|
|
|
var warnings = await _warningQueries.GetWarningRule(systemId, customerId);
|
|
if (warnings == null || warnings.Count == 0)
|
|
{
|
|
RedisHelper.Client.Set(key, new List<WarningRuleCacheDto>(), TimeSpan.FromSeconds(20));
|
|
return new List<ForewarningRuleCacheEntry>();
|
|
}
|
|
|
|
RedisHelper.Client.Set(key, warnings);
|
|
ruleResult = WriteRules(warnings);
|
|
_rules.TryAdd(key, ruleResult);
|
|
return ruleResult;
|
|
}
|
|
}
|
|
|
|
private List<AreaCacheEntry>? GetAreaInfoByAreaId(int areaId)
|
|
{
|
|
if (_areas.TryGetValue(areaId, out var areaInfos)) return areaInfos;
|
|
|
|
var areas = GetAreas(areaId);
|
|
if (areas == null || areas.Count == 0) return null;
|
|
|
|
areaInfos = areas.Select(KpiAreaInfoToEntry).ToList();
|
|
_areas.TryAdd(areaId, areaInfos);
|
|
return areaInfos;
|
|
}
|
|
|
|
AreaCacheEntry KpiAreaInfoToEntry(KpiAreaInfo model)
|
|
{
|
|
return new AreaCacheEntry
|
|
{
|
|
Country = model.Country,
|
|
Province = model.Province,
|
|
City = model.City,
|
|
LeftPostcode = model.LeftPostcode,
|
|
RightPostcode = model.RightPostcode
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取区域
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private List<KpiAreaInfo>? GetAreas(int areaId)
|
|
{
|
|
var key = AreaKey(areaId);
|
|
var result = RedisHelper.Client.Get<List<KpiAreaInfo>>(key);
|
|
if (result == null)
|
|
{
|
|
result = RedisHelper.Client.Get<List<KpiAreaInfo>>(key);
|
|
if (result != null) return new List<KpiAreaInfo>();
|
|
|
|
var kpiArea = _kpiAreaRepository.GetAreaInfosByAreaId(areaId);
|
|
if (kpiArea == null)
|
|
{
|
|
RedisHelper.Client.Set(key, new List<KpiAreaInfo>(), TimeSpan.FromSeconds(20));
|
|
return new List<KpiAreaInfo>();
|
|
}
|
|
|
|
RedisHelper.Client.Set(key, kpiArea);
|
|
return kpiArea;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private async Task PublishEvent(ClearRulCacheEvent @event)
|
|
{
|
|
await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, @event.ToJson());
|
|
}
|
|
} |