From a1ae86dcfbc2d1f502b317dcc63ee35ec5164137 Mon Sep 17 00:00:00 2001 From: hardstylewyl <827778732@qq.com> Date: Sun, 27 Apr 2025 11:17:59 +0800 Subject: [PATCH] =?UTF-8?q?perf:=E4=BC=98=E5=8C=96=E8=BD=A8=E8=BF=B9?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=B8=BA=E6=89=B9=E9=87=8F=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=A9=BA=E5=85=A5=E5=8F=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/ProvideServices/DeleteOrderInput.cs | 4 +- .../Events/TrackDeleteEvent.cs | 16 +-- .../EventHandlers/TrackDeleteEventHandler.cs | 39 ++--- .../Services/ProvideServices/OrderService.cs | 10 +- .../Services/ProvideServices/TrackService.cs | 135 +++++++++--------- .../ITrackDetailsEsRepository.cs | 2 + .../Repositories/TrackDetailsEsRepository.cs | 24 +++- 7 files changed, 124 insertions(+), 106 deletions(-) diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs index 633a550e..4f1795c3 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs @@ -11,12 +11,12 @@ public class DeleteTrackInput : OrderNoInfo /// /// 轨迹标识符集合,为支持esid删除,所以非必填 /// - public List? TrackIdentifiers { get; set; } = new(); + public List TrackIdentifiers { get; set; } = new(); /// /// 轨迹ESId集合,非必填,如果有优先级最高 /// - public List? EsIds { get; set; } + public List EsIds { get; set; } = new(); /// /// 重复的情况下,用什么字段比较 diff --git a/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs index 22970d3e..0b0ce375 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs @@ -4,20 +4,20 @@ namespace SJZY.Track.Application.Contract.Events; public class TrackDeleteEvent { + /// + /// 根据esId定位轨迹,优先级最高 + /// + public string[] EsIds { get; set; } = Array.Empty(); + /// /// 子系统id /// public int SubSystemId { get; set; } - /// - /// es中的id - /// - public string[]? EsIds { get; set; } - /// /// 订单ids /// - public int[] OrderIds { get; set; } = null!; + public int[] OrderIds { get; set; } = Array.Empty(); /// /// 重复的情况下,用什么字段比较 @@ -37,7 +37,7 @@ public class TrackDeleteEvent /// /// 轨迹标识符 /// - public List? TrackIdentifiers { get; set; } + public List TrackIdentifiers { get; set; } = new(); /// /// 操作人 @@ -57,6 +57,6 @@ public class TrackDeleteEvent public override string ToString() { return $"[TrackDelete by {OperationMan}] SubSystemId: {SubSystemId}, OrderIds: {string.Join(",", - OrderIds)}, TrackCodes: {string.Join(",", TrackIdentifiers.Select(x=>x.TrackCode))}"; + OrderIds)}, TrackCodes: {string.Join(",", TrackIdentifiers.Select(x => x.TrackCode))}"; } } diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs index 571599b4..89207bee 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs @@ -26,11 +26,15 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe private readonly IBroadcastingService _broadcastingService; private readonly IServiceProvider _serviceProvider; - public TrackDeleteEventHandler(IProvideQueries provideQueries, - IOrderRepository orderRepository, ICapPublisher capPublisher, + public TrackDeleteEventHandler( + IProvideQueries provideQueries, + IOrderRepository orderRepository, + ICapPublisher capPublisher, ITrackDetailsEsRepository trackDetailsEsRepository, IOrderOperationRecordEsRepository orderOperationRecordEsRepository, - IBroadcastingService broadcastingService, IServiceProvider serviceProvider) + IBroadcastingService broadcastingService, + IServiceProvider serviceProvider + ) { _provideQueries = provideQueries; _orderRepository = orderRepository; @@ -65,8 +69,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(@event.OrderIds); foreach (var orderId in @event.OrderIds) { - foreach (var group in linkedOrders.Where(x => x.OwnerOrderId == orderId) - .GroupBy(x => x.SubSystemId)) + foreach (var group in linkedOrders.Where(x => x.OwnerOrderId == orderId).GroupBy(x => x.SubSystemId)) { var nextEvent = @event.DeepCopy(); nextEvent.Visited.AddRange(@event.OrderIds); @@ -76,9 +79,11 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe // 不同子系统需要做内容映射 if (@event.SubSystemId != nextEvent.SubSystemId) { - var codeMaps = await _provideQueries - .GetTrackCodeMapsAsync(@event.SubSystemId, nextEvent.SubSystemId, - @event.TrackIdentifiers.Select(x => x.TrackCode).ToArray()); + var codeMaps = await _provideQueries.GetTrackCodeMapsAsync( + @event.SubSystemId, + nextEvent.SubSystemId, + @event.TrackIdentifiers.Select(x => x.TrackCode).ToArray() + ); if (codeMaps.Count == 0) { @@ -133,7 +138,8 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe List orderIds; List tracks; List deleteTracks; - if (@event.EsIds != null && @event.EsIds.Any()) //根据明确的esid进行删除 + // 优先根据EsId查询轨迹 + if (@event.EsIds.Length > 0) //根据明确的esid进行删除 { deleteTracks = await _trackDetailsEsRepository.GetDataByIds(@event.EsIds); orderIds = deleteTracks.Select(m => m.OrderId).Distinct().ToList(); @@ -145,17 +151,14 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe }).ToList(); // 外部api获取的轨迹不允许删除 - if (deleteTracks.Any(m => m.Source == TrackSourceEnum.ExternalServiceProvide.GetHashCode())) + if (deleteTracks.Any(m => m.Source == (int) TrackSourceEnum.ExternalServiceProvide)) return deleteTracks; //查出订单下的所有轨迹,以供后面回退使用 tracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds); - // 删除轨迹 - foreach (var item in deleteTracks) - { - await _trackDetailsEsRepository.DeleteTrackByIdAsync(item.Id, item.IndexName); - } + // 删除轨迹批量 + await _trackDetailsEsRepository.DeleteTrackByIdsAsync(deleteTracks.Select(x => x.Id).ToHashSet()); //清理已经删除过的esid @event.EsIds = Array.Empty(); @@ -202,10 +205,8 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe if (deleteTracks.Count == 0) return deleteTracks; - foreach (var track in deleteTracks) - { - await _trackDetailsEsRepository.DeleteTrackByIdAsync(track.Id, track.IndexName); - } + // 删除轨迹批量 + await _trackDetailsEsRepository.DeleteTrackByIdsAsync(deleteTracks.Select(x => x.Id).ToHashSet()); //从被删除轨迹寻找订单id,稍后会更新订单主表 orderIds = deleteTracks.Select(m => m.OrderId).Distinct().ToList(); diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs index 77f06254..5c2f4da7 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs @@ -20,11 +20,13 @@ public partial class OrderService : ApplicationService, IOrderService private readonly IOrderRepository _orderRepository; private readonly IServiceProvider _serviceProvider; - public OrderService(IOrderRepository orderRepository, - ICapPublisher capPublisher - , ITrackDetailsEsRepository trackDetailsEsRepository, + public OrderService( + IOrderRepository orderRepository, + ICapPublisher capPublisher, + ITrackDetailsEsRepository trackDetailsEsRepository, IOrderOperationRecordEsRepository orderOperationRecordEsRepository, - IServiceProvider serviceProvider) + IServiceProvider serviceProvider + ) { _orderRepository = orderRepository; _orderOperationRecordEsRepository = orderOperationRecordEsRepository; diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs index 8e1de010..dd4d3b9f 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs @@ -31,14 +31,16 @@ public partial class TrackService : ApplicationService, ITrackService private readonly IHttpClientProxy _requestCurrentUserService; private readonly ITrackContentRepository _trackContentRepository; - public TrackService(IOrderRepository orderRepository, + public TrackService( + IOrderRepository orderRepository, ICapPublisher capPublisher, ITrackDetailsEsRepository trackDetailsEsRepository, ITrackContentRepository trackContentRepository, IHttpClientProxy requestCurrentUserService, ITrackTemplateRepository trackTemplateRepository, IHttpContextAccessor contextAccessor, - IVSystemQueries vSystemQueries) + IVSystemQueries vSystemQueries + ) { _orderRepository = orderRepository; _capPublisher = capPublisher; @@ -59,10 +61,12 @@ public partial class TrackService : ApplicationService, ITrackService [HttpPost("Track/Delete")] public async Task DeleteTrackAsync(DeleteTrackInput input) { - var orderId = await _orderRepository.GetFirstAsync( - x => x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, + var orderId = await _orderRepository.GetFirstAsync(x => + x.SubSystemId == input.SubSystemId + && x.OrderType == input.OrderType + && x.OrderNo == input.OrderNo, x => x.Id); - if (orderId == null) + if (orderId == 0) { throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); } @@ -73,38 +77,29 @@ public partial class TrackService : ApplicationService, ITrackService throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); } - var name = userInfo.Data.UserName; - - List tracks; - bool existsExternal; - var esIds = input.EsIds?.Distinct().ToArray(); - //优先使用esId - if (esIds != null && esIds.Length > 0) + // 查询轨迹优先使用esId,tips:考虑删除事件处理直接通过EsId而不是再查询一遍? + List? tracks = null; + var esIds = input.EsIds.Distinct().ToArray(); + if (esIds.Length > 0) { tracks = await _trackDetailsEsRepository.GetDataByIds(esIds); - existsExternal = tracks.Any(x => x.Source == (int) TrackSourceEnum.ExternalServiceProvide); } - else + else if (input.TrackIdentifiers.Count > 0) { - var trackCodes = input.TrackIdentifiers?.Select(x => x.TrackCode).ToList(); - var trackIds = input.TrackIdentifiers?.Select(y => $"{y.TrackCode}{y.TrackTime}").ToHashSet(); - //没有任何需要操作的轨迹 - if (trackIds == null || trackIds.Count == 0) - { - throw new BusinessException(message: "没有任何轨迹要删除,请检查输入参数"); - } - - //删除轨迹约束,只要其中有一条来源是外部的就立即返回错误 + // todo:漏洞,使用标识符(code+时间)删除缺少时区补充 + var trackCodes = input.TrackIdentifiers.Select(x => x.TrackCode).ToList(); + var trackIds = input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}").ToHashSet(); tracks = await _trackDetailsEsRepository.GetListAsync(new[] { orderId }, trackCodes); - //检查删除的轨迹中是否包含外部轨迹 - existsExternal = tracks - .Where(x => x.Source == (int) TrackSourceEnum.ExternalServiceProvide) + + // todo:漏洞,如果是外部服务商轨迹(拉取得到的轨迹),没有扩展? + tracks = tracks + // 先通过code+时间初步过滤 + .Where(y => trackIds.Contains($"{y.TrackCode}{y.TrackTime}")) + // 如果提供了比较字段,则进一步过滤,但要求这个code的所有轨迹都要包含Extra! .WhereIf(!input.CompareFields.IsNullOrWhiteSpace(), y => { if (string.IsNullOrWhiteSpace(y.Extra)) - { throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹"); - } var extraDict = System.Text.Json.JsonSerializer.Deserialize>(y.Extra); if (extraDict!.TryGetValue(input.CompareFields!, out var compareValueJsonElement)) @@ -112,47 +107,47 @@ public partial class TrackService : ApplicationService, ITrackService return false; }) - .Select(x => $"{x.TrackCode}{x.TrackTime}") - .Any(x => trackIds.Contains(x)); + .ToList(); } - if (existsExternal) - { - throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除"); - } - - if (tracks.Count == 0) + if (tracks == null || tracks.Count == 0) { throw new BusinessException(message: "没有任何轨迹要删除,请检查输入参数"); } - // 删除轨迹 - await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, - new TrackDeleteEvent - { - EsIds = input.EsIds?.ToArray(), - OrderIds = new[] { orderId }, - CompareFields = input.CompareFields, - CompareValue = input.CompareValue, - Source = input.Source, - TrackIdentifiers = input.TrackIdentifiers, - SubSystemId = input.SubSystemId, - OperationMan = name - }); + //删除轨迹约束,只要其中有一条来源是外部的就立即返回错误 + if (tracks.Any(x => x.Source == (int) TrackSourceEnum.ExternalServiceProvide)) + { + throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除"); + } + + // 删除轨迹(异步) + await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, new TrackDeleteEvent + { + EsIds = esIds, + OrderIds = new[] { orderId }, + SubSystemId = input.SubSystemId, + CompareFields = input.CompareFields, + CompareValue = input.CompareValue, + Source = input.Source, + TrackIdentifiers = input.TrackIdentifiers, + OperationMan = userInfo.Data.UserName + }); return new UnifyResultDto(true, true); } /// - /// 根据esid删除轨迹内容 + /// 根据esid删除轨迹内容(FBA专用) /// /// /// [HttpPost("Track/BatchDeleteByEsId")] public async Task BatchDeleteTrackByEsIdAsync(BatchDeleteTrackByEsIdInput input) { - var tracks = await _trackDetailsEsRepository.GetDataByIds(input.TrackContentEsIds.ToArray()); - if (tracks == null || tracks.Count == 0) + var esIds = input.TrackContentEsIds.ToArray(); + var tracks = await _trackDetailsEsRepository.GetDataByIds(esIds); + if (tracks.Count == 0) return new UnifyResultDto(false, "未找到指定id下的轨迹内容"); if (tracks.Any(m => m.Source == TrackSourceEnum.ExternalServiceProvide.GetHashCode())) @@ -176,7 +171,7 @@ public partial class TrackService : ApplicationService, ITrackService var @event = new TrackDeleteEvent { - EsIds = input.TrackContentEsIds.ToArray(), + EsIds = esIds, SubSystemId = tracks.First().SubSystemId, Source = input.Source, OperationMan = userName, @@ -198,36 +193,28 @@ public partial class TrackService : ApplicationService, ITrackService { input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 var orderIds = await _orderRepository.GetListAsync(x => - x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && - input.OrderNos.Contains(x.OrderNo) - , x => x.Id); + x.SubSystemId == input.SubSystemId + && x.OrderType == input.OrderType + && input.OrderNos.Contains(x.OrderNo), + x => x.Id); if (orderIds.Count == 0) { throw new BusinessException(message: "订单一个都不存在"); } - // 获取用户name - var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); - if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) - { - throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); - } - //删除轨迹约束,只要其中有一条来源是外部的就立即返回错误 - var tracks = await _trackDetailsEsRepository - .GetListAsync(orderIds.ToArray(), - input.TrackIdentifiers.Select(x => x.TrackCode).ToList(), - TrackSourceEnum.ExternalServiceProvide); + var tracks = await _trackDetailsEsRepository.GetListAsync(orderIds.ToArray(), + input.TrackIdentifiers.Select(x => x.TrackCode).ToList(), + TrackSourceEnum.ExternalServiceProvide + ); //当要删除的轨迹标识出现交叉则不允许删除 var intersect = tracks .WhereIf(!input.CompareFields.IsNullOrWhiteSpace(), y => { if (string.IsNullOrWhiteSpace(y.Extra)) - { throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹"); - } var extraDict = TextJsonHelper.DeserializeToDictionary(y.Extra); if (extraDict!.TryGetValue(input.CompareFields!, out var compareValueJsonElement)) @@ -236,12 +223,20 @@ public partial class TrackService : ApplicationService, ITrackService return false; }) .Select(x => $"{x.TrackCode}{x.TrackTime}") - .Intersect(input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}")).ToList(); + .Intersect(input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}")) + .ToList(); if (intersect.Count > 0) { throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除"); } + // 获取用户name + var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); + if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) + { + throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); + } + // 删除轨迹 var @event = new TrackDeleteEvent { diff --git a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs index 72f49807..840b2d51 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs @@ -41,6 +41,8 @@ public interface ITrackDetailsEsRepository : IElasticsearchClientService esIds); + Task> GetDataByIds(string[] ids); Task GetDetailAsync(string orderNo, string trackCode, int orderType, int subSystemId, DateTime trackTime); diff --git a/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs index 22998be5..e6415867 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs @@ -691,7 +691,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x .Index(GlobalConst.TrackDetailsIndex) .Version() - .Query(q => query) + .Query(_ => query) .Size(SafelyLimit) .Sort(s => s .Field(f => f.ZeroTrackTime, SortOrder.Descending) @@ -774,16 +774,34 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract esIds) + { + var r = await Context.DeleteByQueryAsync(x => x + .Index(GlobalConst.TrackDetailsIndex) + .Query(q => q.Ids(i => i.Values(esIds))) + ); + + if (!r.IsValid) + { + throw new InvalidOperationException($"轨迹删除失败,ids:[{string.Join(", ", esIds)}],原因:{r.DebugInformation}。"); + } + } + public async Task> GetDataByIds(string[] ids) { - var res = await Context.SearchAsync(m => m + var r = await Context.SearchAsync(m => m .Index(GlobalConst.TrackDetailsIndex) .Version() .Query( q => q.Ids(i => i.Values(ids)) )); - return res.ToIdAndVersionList(); + if (!r.IsValid) + { + throw new InvalidOperationException($"轨迹查询失败,ids:[{string.Join(", ", ids)}],原因:{r.DebugInformation}。"); + } + + return r.ToIdAndVersionList(); } public async Task GetDetailAsync(string orderNo, string trackCode, int orderType, int subSystemId, DateTime trackTime)