From 14048080d73a7a6b402a750c9f9a84e9a5ae449c Mon Sep 17 00:00:00 2001 From: zzh <1368735060@qq.com> Date: Wed, 21 Oct 2026 10:29:34 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=E8=BD=A8=E8=BF=B9=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E5=88=97=E8=A1=A8=E6=94=AF=E6=8C=81=E8=A1=A8=E5=A4=B4?= =?UTF-8?q?=E5=85=A8=E5=AD=97=E6=AE=B5=E7=AD=9B=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- .../ProvideServices/GetPageTrackOrderInput.cs | 105 ++++++++++ .../Dtos/Order/GetPageTrackOrderInputVO.cs | 105 ++++++++++ .../Repositories/OrderRepository.cs | 198 ++++++++++-------- 3 files changed, 320 insertions(+), 88 deletions(-) diff --git a/src/TrackCenter.Application/Dtos/ProvideServices/GetPageTrackOrderInput.cs b/src/TrackCenter.Application/Dtos/ProvideServices/GetPageTrackOrderInput.cs index 24f24b2d..7e9b1d55 100644 --- a/src/TrackCenter.Application/Dtos/ProvideServices/GetPageTrackOrderInput.cs +++ b/src/TrackCenter.Application/Dtos/ProvideServices/GetPageTrackOrderInput.cs @@ -46,6 +46,111 @@ public class GetPageTrackOrderInput : PageInfoInput /// 创建时间截止 /// public DateTime? CreateTimeEnd { get; set; } + + /// + /// 尾程单号(支持逗号分隔多值,等值匹配) + /// + public string? TrackNo { get; set; } + + /// + /// 其他单号(支持逗号分隔多值,等值匹配) + /// + public string? OtherNo { get; set; } + + /// + /// 销售产品 + /// + public string? Product { get; set; } + + /// + /// 渠道 + /// + public string? Channel { get; set; } + + /// + /// API 编码 / 服务商代码 + /// + public string? ApiCode { get; set; } + + /// + /// 国家编码 + /// + public string? CountryCode { get; set; } + + /// + /// 州省 + /// + public string? Province { get; set; } + + /// + /// 城市 + /// + public string? City { get; set; } + + /// + /// 邮编 + /// + public string? Postcode { get; set; } + + /// + /// 邮箱 + /// + public string? Email { get; set; } + + /// + /// 最新轨迹状态 + /// + public string? NewestTrackStatus { get; set; } + + /// + /// 最新轨迹内容 + /// + public string? NewestTrackContent { get; set; } + + /// + /// 最新轨迹内容英文 + /// + public string? NewestTrackEnContent { get; set; } + + /// + /// 最新轨迹发生地 + /// + public string? NewestTrackPlace { get; set; } + + /// + /// 最新轨迹时间开始 + /// + public DateTime? NewestTrackTimeStart { get; set; } + + /// + /// 最新轨迹时间截止 + /// + public DateTime? NewestTrackTimeEnd { get; set; } + + /// + /// 最新轨迹时区 + /// + public float? NewestTrackTimeZone { get; set; } + + /// + /// 是否完结 + /// + public bool? IsFinish { get; set; } + + /// + /// 预计到达时间开始 + /// + public DateTime? EstimatedDeliveryDateStart { get; set; } + + /// + /// 预计到达时间截止 + /// + public DateTime? EstimatedDeliveryDateEnd { get; set; } + + /// + /// 目的地时区 + /// + public float? DestinationTimeZone { get; set; } } /// diff --git a/src/TrackCenter.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs b/src/TrackCenter.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs index 5af210cd..6c02e225 100644 --- a/src/TrackCenter.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs +++ b/src/TrackCenter.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs @@ -41,6 +41,111 @@ public class GetPageTrackOrderInputVO : PageInfoInput /// 创建时间截止 /// public DateTime? CreateTimeEnd { get; set; } + + /// + /// 尾程单号(支持逗号分隔多值,等值匹配) + /// + public string? TrackNo { get; set; } + + /// + /// 其他单号(支持逗号分隔多值,等值匹配) + /// + public string? OtherNo { get; set; } + + /// + /// 销售产品 + /// + public string? Product { get; set; } + + /// + /// 渠道 + /// + public string? Channel { get; set; } + + /// + /// API 编码 / 服务商代码 + /// + public string? ApiCode { get; set; } + + /// + /// 国家编码 + /// + public string? CountryCode { get; set; } + + /// + /// 州省 + /// + public string? Province { get; set; } + + /// + /// 城市 + /// + public string? City { get; set; } + + /// + /// 邮编 + /// + public string? Postcode { get; set; } + + /// + /// 邮箱 + /// + public string? Email { get; set; } + + /// + /// 最新轨迹状态 + /// + public string? NewestTrackStatus { get; set; } + + /// + /// 最新轨迹内容 + /// + public string? NewestTrackContent { get; set; } + + /// + /// 最新轨迹内容英文 + /// + public string? NewestTrackEnContent { get; set; } + + /// + /// 最新轨迹发生地 + /// + public string? NewestTrackPlace { get; set; } + + /// + /// 最新轨迹时间开始 + /// + public DateTime? NewestTrackTimeStart { get; set; } + + /// + /// 最新轨迹时间截止 + /// + public DateTime? NewestTrackTimeEnd { get; set; } + + /// + /// 最新轨迹时区 + /// + public float? NewestTrackTimeZone { get; set; } + + /// + /// 是否完结 + /// + public bool? IsFinish { get; set; } + + /// + /// 预计到达时间开始 + /// + public DateTime? EstimatedDeliveryDateStart { get; set; } + + /// + /// 预计到达时间截止 + /// + public DateTime? EstimatedDeliveryDateEnd { get; set; } + + /// + /// 目的地时区 + /// + public float? DestinationTimeZone { get; set; } } /// diff --git a/src/TrackCenter.Repository/Repositories/OrderRepository.cs b/src/TrackCenter.Repository/Repositories/OrderRepository.cs index 0067abf6..e5a4d057 100644 --- a/src/TrackCenter.Repository/Repositories/OrderRepository.cs +++ b/src/TrackCenter.Repository/Repositories/OrderRepository.cs @@ -19,56 +19,14 @@ public class OrderRepository : BasicRepository, IOrderRepository, I } public async Task> GetTrackOrderPagedList(GetPageTrackOrderInputVO input) { - //查询完去重 PagedResult pageList; - //没传递单号时 if (input.OrderNos.IsNullOrEmpty()) { - pageList = await Context.Queryable() - .WhereIF(!input.AppKey.IsNullOrWhiteSpace(), a => a.AppKey == input.AppKey) - .WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue, - a => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd) - .WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue), - a => a.CreateTime >= input.CreateTimeStart) - .WhereIF((!input.CreateTimeStart.HasValue) && input.CreateTimeEnd.HasValue, - a => a.CreateTime <= input.CreateTimeEnd) - .WhereIF(!input.Customer.IsNullOrWhiteSpace(), a => a.Customer.Contains(input.Customer!)) - .WhereIF(input.TrackOrderType > 0, a => a.OrderType == input.TrackOrderType) - .WhereIF(input.TabType > 0, a => a.QuestionType == input.TabType) - .WhereIF(input.TabType == TrackProblemType.Warn, a => !a.IsCompleted) + pageList = await ApplyTrackOrderListFilters(Context.Queryable(), input) .OrderByDescending(a => a.CreateTime) - .Select(a => new TrackOrderVO - { - Id = a.Id, - OrderNumber = a.OrderNo, - OrderType = a.OrderType, - QuestionType = a.QuestionType, - Customer = a.Customer, - NewestTrackStatus = a.LatestTrackStatus, - NewestTrackContent = a.LatestTrackContent, - NewestTrackEnContent = a.LatestTrackEnContent, - NewestTrackPlace = a.LatestTrackPlace, - NewestTrackTime = a.LatestTrackTime, - NewestTrackTimeZone = a.LatestTrackTimeZone, - IsFinish = a.IsCompleted, - CreateTime = a.CreateTime, - AppKey = a.AppKey, - DestinationTimeZone = a.DestinationTimeZone, - EstimatedDeliveryDate = a.EstimatedDeliveryDate, - TrackNo = a.TrackNo, - OtherNo = a.ThirdPartyOrderNumber, - Channel = a.Channel, - Product = a.ProductCode, - ApiCode = a.ServiceProviderCode, - CountryCode = a.ArrivalCountry, - Province = a.ArrivalProvince, - Postcode = a.ArrivalPostCode, - City = a.ArrivalCity, - Email = a.ArrivalEmail - }) + .Select(TrackOrderListSelector) .ToPagedListAsync(input.PageIndex, input.PageSize); } - //传递单号时 else { var orderNos = input.OrderNos!.Distinct().ToList(); @@ -89,59 +47,18 @@ public class OrderRepository : BasicRepository, IOrderRepository, I orderHashset.UnionWith(orderIdsForThirdParty); orderIds = orderHashset.ToList(); - //没有任何单 if (orderIds.Count == 0) { return new PagedResult(); } - pageList = await Context.Queryable() - .Where(a => orderIds.Contains(a.Id)) - .WhereIF(!input.AppKey.IsNullOrWhiteSpace(), a => a.AppKey == input.AppKey) - .WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue, - a => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd) - .WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue), - a => a.CreateTime >= input.CreateTimeStart) - .WhereIF((!input.CreateTimeStart.HasValue) && input.CreateTimeEnd.HasValue, - a => a.CreateTime <= input.CreateTimeEnd) - .WhereIF(!input.Customer.IsNullOrWhiteSpace(), a => a.Customer.Contains(input.Customer!)) - .WhereIF(input.TrackOrderType > 0, a => a.OrderType == input.TrackOrderType) - .WhereIF(input.TabType > 0, a => a.QuestionType == input.TabType) - .WhereIF(input.TabType == TrackProblemType.Warn, a => !a.IsCompleted) + pageList = await ApplyTrackOrderListFilters( + Context.Queryable().Where(a => orderIds.Contains(a.Id)), input) .OrderByDescending(a => a.CreateTime) - .Select(a => new TrackOrderVO - { - Id = a.Id, - OrderNumber = a.OrderNo, - OrderType = a.OrderType, - QuestionType = a.QuestionType, - Customer = a.Customer, - NewestTrackStatus = a.LatestTrackStatus, - NewestTrackContent = a.LatestTrackContent, - NewestTrackEnContent = a.LatestTrackEnContent, - NewestTrackPlace = a.LatestTrackPlace, - NewestTrackTime = a.LatestTrackTime, - NewestTrackTimeZone = a.LatestTrackTimeZone, - IsFinish = a.IsCompleted, - CreateTime = a.CreateTime, - AppKey = a.AppKey, - DestinationTimeZone = a.DestinationTimeZone, - EstimatedDeliveryDate = a.EstimatedDeliveryDate, - TrackNo = a.TrackNo, - OtherNo = a.ThirdPartyOrderNumber, - Channel = a.Channel, - Product = a.ProductCode, - ApiCode = a.ServiceProviderCode, - CountryCode = a.ArrivalCountry, - Province = a.ArrivalProvince, - Postcode = a.ArrivalPostCode, - City = a.ArrivalCity, - Email = a.ArrivalEmail - }) + .Select(TrackOrderListSelector) .ToPagedListAsync(input.PageIndex, input.PageSize); } - //填充数描述信息 pageList.Items.ForEach(x => { x.OrderTypeName = x.OrderType.GetDescription(); @@ -151,6 +68,111 @@ public class OrderRepository : BasicRepository, IOrderRepository, I return pageList; } + private static System.Linq.Expressions.Expression> TrackOrderListSelector => + a => new TrackOrderVO + { + Id = a.Id, + OrderNumber = a.OrderNo, + OrderType = a.OrderType, + QuestionType = a.QuestionType, + Customer = a.Customer, + NewestTrackStatus = a.LatestTrackStatus, + NewestTrackContent = a.LatestTrackContent, + NewestTrackEnContent = a.LatestTrackEnContent, + NewestTrackPlace = a.LatestTrackPlace, + NewestTrackTime = a.LatestTrackTime, + NewestTrackTimeZone = a.LatestTrackTimeZone, + IsFinish = a.IsCompleted, + CreateTime = a.CreateTime, + AppKey = a.AppKey, + DestinationTimeZone = a.DestinationTimeZone, + EstimatedDeliveryDate = a.EstimatedDeliveryDate, + TrackNo = a.TrackNo, + OtherNo = a.ThirdPartyOrderNumber, + Channel = a.Channel, + Product = a.ProductCode, + ApiCode = a.ServiceProviderCode, + CountryCode = a.ArrivalCountry, + Province = a.ArrivalProvince, + Postcode = a.ArrivalPostCode, + City = a.ArrivalCity, + Email = a.ArrivalEmail + }; + + /// + /// 表头筛选:客户/单号/产品/渠道/轨迹内容等 + /// + private static ISugarQueryable ApplyTrackOrderListFilters( + ISugarQueryable query, + GetPageTrackOrderInputVO input) + { + var trackNos = SplitMultiValues(input.TrackNo); + var otherNos = SplitMultiValues(input.OtherNo); + + query = query + .WhereIF(!input.AppKey.IsNullOrWhiteSpace(), a => a.AppKey == input.AppKey) + .WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue, + a => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd) + .WhereIF(input.CreateTimeStart.HasValue && !input.CreateTimeEnd.HasValue, + a => a.CreateTime >= input.CreateTimeStart) + .WhereIF(!input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue, + a => a.CreateTime <= input.CreateTimeEnd) + .WhereIF(!input.Customer.IsNullOrWhiteSpace(), a => a.Customer.Contains(input.Customer!)) + .WhereIF(input.TrackOrderType > 0, a => a.OrderType == input.TrackOrderType) + .WhereIF(input.TabType > 0, a => a.QuestionType == input.TabType) + .WhereIF(input.TabType == TrackProblemType.Warn, a => !a.IsCompleted) + .WhereIF(trackNos.Count == 1, a => a.TrackNo.Contains(trackNos[0])) + .WhereIF(trackNos.Count > 1, a => trackNos.Contains(a.TrackNo)) + .WhereIF(otherNos.Count == 1, a => a.ThirdPartyOrderNumber != null && a.ThirdPartyOrderNumber.Contains(otherNos[0])) + .WhereIF(otherNos.Count > 1, a => a.ThirdPartyOrderNumber != null && otherNos.Contains(a.ThirdPartyOrderNumber)) + .WhereIF(!input.Product.IsNullOrWhiteSpace(), a => a.ProductCode != null && a.ProductCode.Contains(input.Product!)) + .WhereIF(!input.Channel.IsNullOrWhiteSpace(), a => a.Channel != null && a.Channel.Contains(input.Channel!)) + .WhereIF(!input.ApiCode.IsNullOrWhiteSpace(), + a => a.ServiceProviderCode != null && a.ServiceProviderCode.Contains(input.ApiCode!)) + .WhereIF(!input.CountryCode.IsNullOrWhiteSpace(), a => a.ArrivalCountry.Contains(input.CountryCode!)) + .WhereIF(!input.Province.IsNullOrWhiteSpace(), a => a.ArrivalProvince != null && a.ArrivalProvince.Contains(input.Province!)) + .WhereIF(!input.City.IsNullOrWhiteSpace(), a => a.ArrivalCity.Contains(input.City!)) + .WhereIF(!input.Postcode.IsNullOrWhiteSpace(), + a => a.ArrivalPostCode != null && a.ArrivalPostCode.Contains(input.Postcode!)) + .WhereIF(!input.Email.IsNullOrWhiteSpace(), a => a.ArrivalEmail != null && a.ArrivalEmail.Contains(input.Email!)) + .WhereIF(!input.NewestTrackStatus.IsNullOrWhiteSpace(), + a => a.LatestTrackStatus != null && a.LatestTrackStatus.Contains(input.NewestTrackStatus!)) + .WhereIF(!input.NewestTrackContent.IsNullOrWhiteSpace(), + a => a.LatestTrackContent != null && a.LatestTrackContent.Contains(input.NewestTrackContent!)) + .WhereIF(!input.NewestTrackEnContent.IsNullOrWhiteSpace(), + a => a.LatestTrackEnContent != null && a.LatestTrackEnContent.Contains(input.NewestTrackEnContent!)) + .WhereIF(!input.NewestTrackPlace.IsNullOrWhiteSpace(), + a => a.LatestTrackPlace != null && a.LatestTrackPlace.Contains(input.NewestTrackPlace!)) + .WhereIF(input.NewestTrackTimeStart.HasValue && input.NewestTrackTimeEnd.HasValue, + a => a.LatestTrackTime >= input.NewestTrackTimeStart && a.LatestTrackTime <= input.NewestTrackTimeEnd) + .WhereIF(input.NewestTrackTimeStart.HasValue && !input.NewestTrackTimeEnd.HasValue, + a => a.LatestTrackTime >= input.NewestTrackTimeStart) + .WhereIF(!input.NewestTrackTimeStart.HasValue && input.NewestTrackTimeEnd.HasValue, + a => a.LatestTrackTime <= input.NewestTrackTimeEnd) + .WhereIF(input.NewestTrackTimeZone.HasValue, a => a.LatestTrackTimeZone == input.NewestTrackTimeZone) + .WhereIF(input.IsFinish.HasValue, a => a.IsCompleted == input.IsFinish.Value) + .WhereIF(input.EstimatedDeliveryDateStart.HasValue && input.EstimatedDeliveryDateEnd.HasValue, + a => a.EstimatedDeliveryDate >= input.EstimatedDeliveryDateStart && + a.EstimatedDeliveryDate <= input.EstimatedDeliveryDateEnd) + .WhereIF(input.EstimatedDeliveryDateStart.HasValue && !input.EstimatedDeliveryDateEnd.HasValue, + a => a.EstimatedDeliveryDate >= input.EstimatedDeliveryDateStart) + .WhereIF(!input.EstimatedDeliveryDateStart.HasValue && input.EstimatedDeliveryDateEnd.HasValue, + a => a.EstimatedDeliveryDate <= input.EstimatedDeliveryDateEnd) + .WhereIF(input.DestinationTimeZone.HasValue, a => a.DestinationTimeZone == input.DestinationTimeZone); + + return query; + } + + private static List SplitMultiValues(string? raw) + { + if (raw.IsNullOrWhiteSpace()) return new List(); + return raw! + .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + .Where(x => !string.IsNullOrWhiteSpace(x)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + } + public async Task<(int MainOrderId, string OrderNo, string Customer)> GetTrackOrderByProviderAndOrderNo( string serviceProviderCode, string orderNo, string? appKey = null, TrackOrderType? orderType = null) { -- 2.45.2 From 279afebb48f4f2c0197a3ba4ed4288d8bb92dc9c Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Wed, 21 Oct 2026 16:31:45 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20fake=E6=9B=BF=E6=8D=A2cap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Directory.Build.props | 5 +- Directory.Build.targets | 26 ++ Fake.Local.props | 10 + TrackCenter.sln | 2 + src/TrackCenter.Api/TrackCenter.Api.csproj | 5 +- src/TrackCenter.Api/TrackCenterApiModule.cs | 23 ++ src/TrackCenter.Api/appsettings.json | 3 + src/TrackCenter.Application/CAP/CAPFilter.cs | 69 ----- .../CAP/CapNoRetryException.cs | 12 - .../CAP/LoggerExtensions.cs | 90 ------ .../CAP/MySubscribeExecutor.cs | 269 ------------------ .../CAP/SubscriberExecutionFailedException.cs | 15 - .../Events/OrderPodPullEvent.cs | 8 +- .../TrackChangeAfterUpdateOrderEvent.cs | 5 +- .../Events/TrackDeleteEvent.cs | 4 +- .../Events/TrackPushEvent.cs | 5 +- .../Events/TrackUpsertEvent.cs | 4 +- .../Events/TrackUpsertForRefreshEvent.cs | 9 + ...TrackChangeAfterUpdateOrderEventHandler.cs | 13 +- .../TrackDeleteEventHandler.cs | 74 ++--- .../TrackPushEventHandler.cs | 65 ++--- .../TrackUpsertEventHandler.cs | 232 ++++++++------- .../Rabbit/TrackPushCompletedEventHandler.cs | 2 +- .../Rabbit/TrackRefreshEventHandler.cs | 10 +- .../ProvideServices/OrderService.Link.cs | 25 +- .../OrderService.PullConfigs.cs | 6 +- .../ProvideServices/OrderService.V2.cs | 36 +-- .../Services/ProvideServices/OrderService.cs | 39 +-- .../ProvideServices/TrackPullService.cs | 25 +- .../ProvideServices/TrackPushService.cs | 15 +- .../ProvideServices/TrackService.Query.cs | 2 +- .../Services/ProvideServices/TrackService.cs | 58 ++-- .../Services/TimerTaskss/TrackPullTask.cs | 12 +- .../Services/TrackOrders/TrackOrderService.cs | 51 ++-- .../Services/Warning/ReturnWarningService.cs | 15 +- .../TrackCenter.Application.csproj | 9 +- .../TrackCenterApplicationModule.cs | 61 ---- 37 files changed, 407 insertions(+), 907 deletions(-) create mode 100644 Directory.Build.targets create mode 100644 Fake.Local.props delete mode 100644 src/TrackCenter.Application/CAP/CAPFilter.cs delete mode 100644 src/TrackCenter.Application/CAP/CapNoRetryException.cs delete mode 100644 src/TrackCenter.Application/CAP/LoggerExtensions.cs delete mode 100644 src/TrackCenter.Application/CAP/MySubscribeExecutor.cs delete mode 100644 src/TrackCenter.Application/CAP/SubscriberExecutionFailedException.cs create mode 100644 src/TrackCenter.Application/Events/TrackUpsertForRefreshEvent.cs rename src/TrackCenter.Application/{CAP/EventHandlers => Messaging}/TrackChangeAfterUpdateOrderEventHandler.cs (93%) rename src/TrackCenter.Application/{CAP/EventHandlers => Messaging}/TrackDeleteEventHandler.cs (80%) rename src/TrackCenter.Application/{CAP/EventHandlers => Messaging}/TrackPushEventHandler.cs (91%) rename src/TrackCenter.Application/{CAP/EventHandlers => Messaging}/TrackUpsertEventHandler.cs (71%) diff --git a/Directory.Build.props b/Directory.Build.props index 7d6f04d0..1f5eaf03 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,9 @@ + + - 8.0.5.17 + + 8.0.6 diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 00000000..34e847f5 --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,26 @@ + + + + + <_LocalFakeCandidate Include="@(PackageReference -> '$(FakeRepoRoot)\src\%(Identity)\%(Identity).csproj')" /> + <_LocalFakeCandidate Include="@(PackageReference -> '$(FakeRepoRoot)\modules\rbac\%(Identity)\%(Identity).csproj')" /> + <_LocalFakeCandidate Include="@(PackageReference -> '$(FakeRepoRoot)\modules\file-management\%(Identity)\%(Identity).csproj')" /> + + + + + + + + + + <_MissingLocalFake Include="@(_LocalFakeCandidate)" Condition="!Exists('%(Identity)')" /> + + + + diff --git a/Fake.Local.props b/Fake.Local.props new file mode 100644 index 00000000..8519e293 --- /dev/null +++ b/Fake.Local.props @@ -0,0 +1,10 @@ + + + + C:\Users\BSI\RiderProjects\fake2 + false + + diff --git a/TrackCenter.sln b/TrackCenter.sln index 3bb0c534..06261b70 100644 --- a/TrackCenter.sln +++ b/TrackCenter.sln @@ -20,6 +20,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution items", "solution .editorconfig = .editorconfig Directory.Build.props = Directory.Build.props .gitea\workflows\deploy.yml = .gitea\workflows\deploy.yml + Fake.Local.props = Fake.Local.props + Directory.Build.targets = Directory.Build.targets EndProjectSection EndProject Global diff --git a/src/TrackCenter.Api/TrackCenter.Api.csproj b/src/TrackCenter.Api/TrackCenter.Api.csproj index 7022770f..48e85830 100644 --- a/src/TrackCenter.Api/TrackCenter.Api.csproj +++ b/src/TrackCenter.Api/TrackCenter.Api.csproj @@ -1,4 +1,4 @@ - + @@ -20,6 +20,9 @@ + + + diff --git a/src/TrackCenter.Api/TrackCenterApiModule.cs b/src/TrackCenter.Api/TrackCenterApiModule.cs index 4681cf88..7af17e9d 100644 --- a/src/TrackCenter.Api/TrackCenterApiModule.cs +++ b/src/TrackCenter.Api/TrackCenterApiModule.cs @@ -5,6 +5,8 @@ using Fake.AspNetCore.ExceptionHandling; using Fake.AspNetCore.Newtonsoft; using Fake.AspNetCore.Swagger; using Fake.Autofac; +using Fake.EventBus.Dashboard; +using Fake.EventBus.IntegrationEventLog; using Fake.FeiShu; using Fake.Json; using Fake.Modularity; @@ -15,6 +17,7 @@ using Hangfire; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Mvc.Authorization; +using Microsoft.EntityFrameworkCore; using OpenTelemetry.Resources; using OpenTelemetry.Trace; using TrackCenter.Application; @@ -30,6 +33,9 @@ namespace TrackCenter.Api; [DependsOn(typeof(FakeAspNetCoreModule))] [DependsOn(typeof(TrackCenterApplicationModule))] [DependsOn(typeof(TrackCenterRepositoryModule))] +// RabbitMQ 物理总线之后 Replace IDistributedEventBus → Outbox(与 admin 一致) +[DependsOn(typeof(FakeEventBusIntegrationEventLogModule))] +[DependsOn(typeof(FakeEventBusDashboardModule))] [DependsOn(typeof(FakeSerilogModule))] public class TrackCenterApiModule : FakeModule { @@ -53,6 +59,20 @@ public class TrackCenterApiModule : FakeModule // 配置签名验证选项 services.Configure(configuration.GetSection("SignatureValidation")); + // Outbox / Inbox 与业务同库(EF),通过 DbTransaction 征用 SqlSugar 事务 + services.AddDbContext(options => + { + var connectionString = configuration.GetConnectionString("IntegrationEventLog") + ?? configuration.GetConnectionString("Default") + ?? configuration["ConnectionStrings:Default"] + ?? string.Empty; + var serverVersion = ServerVersion.AutoDetect(connectionString); + options.UseMySql(connectionString, serverVersion); +#if DEBUG + options.EnableSensitiveDataLogging(); +#endif + }); + // 全局授权配置:所有接口默认需要授权 services.AddMvc(options => { @@ -186,6 +206,9 @@ public class TrackCenterApiModule : FakeModule Authorization = [new AnonymousHangfireAuthorizationFilter()] }); + // 必须在 UsePathBase 之后:完整对外路径为 {PathBase}/eventbus + app.UseFakeEventBusDashboard(); + app.Services.GetRequiredService().Send("Application started"); } } diff --git a/src/TrackCenter.Api/appsettings.json b/src/TrackCenter.Api/appsettings.json index 06ba18d7..c004a63e 100644 --- a/src/TrackCenter.Api/appsettings.json +++ b/src/TrackCenter.Api/appsettings.json @@ -3,5 +3,8 @@ "Consul": { "Address": "http://test.ideship.com:30850", "Token": "c0aea902-dca0-ac29-299b-a0d47e5402aa" + }, + "DataSeed": { + "Enable": false } } diff --git a/src/TrackCenter.Application/CAP/CAPFilter.cs b/src/TrackCenter.Application/CAP/CAPFilter.cs deleted file mode 100644 index 9e79b526..00000000 --- a/src/TrackCenter.Application/CAP/CAPFilter.cs +++ /dev/null @@ -1,69 +0,0 @@ -using DotNetCore.CAP.Filter; -using InterfaceForward.Domain.Shared.Helpers; -using TrackCenter.Application.Helpers; - -namespace TrackCenter.Application.CAP; - -public class CapFilter : SubscribeFilter -{ - /// - /// 执行前 - /// - /// - /// - public override async Task OnSubscribeExecutingAsync(ExecutingContext context) - { - // 轨迹新增、更新要做幂等 - if (!context.DeliverMessage.Headers["cap-msg-name"] - .IsIn(GlobalConst.TrackUpsertSubscribe, GlobalConst.TrackManualPushSubscribe)) return; - var argumentJsonStr = context.Arguments.ToJson(); - - if (!string.IsNullOrEmpty(argumentJsonStr)) - { - context.DeliverMessage.Headers.TryGetValue("track-arguments-hash", out var hash); - if (hash.IsNullOrEmpty()) // 计算参数hash - { - hash = StringHelper.GetHash(argumentJsonStr); - context.DeliverMessage.Headers["track-arguments-hash"] = hash; - } - - if (await RedisHelper.Client.ExistsAsync($"CapExecuteFilter:{hash}{DateTime.Now:G}")) - { - throw new CapNoRetryException($"检测到重复消费,消费参数:{argumentJsonStr}"); - } - } - } - - public override async Task OnSubscribeExecutedAsync(ExecutedContext context) - { - context.DeliverMessage.Headers.TryGetValue("track-arguments-hash", out var hash); - if (!hash.IsNullOrEmpty()) - { - await RedisHelper.Client.SetAsync($"CapExecuteFilter:{hash}{DateTime.Now:G}", 1, TimeSpan.FromMinutes(3)); - } - } - - /// - /// 消费异常事件 - /// - /// - /// - public override Task OnSubscribeExceptionAsync(ExceptionContext context) - { - context.DeliverMessage.Headers.TryGetValue("cap-msg-id", out var messageId); - - if (context.Exception is CapNoRetryException ex) - { - context.ExceptionHandled = true; - Log.Warning(ex.ToString(), true); - } - else - { - // 发飞书,异常继续上抛,进入重试机制 - // tips:重试有冷却期(默认4分钟) - Log.Error($"cap-msg-id:{messageId}\n{context.Exception}"); - } - - return Task.CompletedTask; - } -} diff --git a/src/TrackCenter.Application/CAP/CapNoRetryException.cs b/src/TrackCenter.Application/CAP/CapNoRetryException.cs deleted file mode 100644 index 4047a271..00000000 --- a/src/TrackCenter.Application/CAP/CapNoRetryException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Fake; -using Fake.ExceptionHandling; -using Fake.Logging; -using Microsoft.Extensions.Logging; - -namespace TrackCenter.Application.CAP; - -public class CapNoRetryException(string? message = null, Exception? innerException = null) - : FakeException(message, innerException), IHasLogLevel -{ - public LogLevel LogLevel { get; set; } = LogLevel.Warning; -} diff --git a/src/TrackCenter.Application/CAP/LoggerExtensions.cs b/src/TrackCenter.Application/CAP/LoggerExtensions.cs deleted file mode 100644 index aadf7184..00000000 --- a/src/TrackCenter.Application/CAP/LoggerExtensions.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Microsoft.Extensions.Logging; -using ILogger = Microsoft.Extensions.Logging.ILogger; - -namespace TrackCenter.Application.CAP; - -internal static class LoggerExtensions -{ - public static void ConsumerExecutedAfterThreshold(this ILogger logger, string messageId, int retries) - { - logger.LogWarning( - $"The Subscriber of the message({messageId}) still fails after {retries}th executions and we will stop retrying."); - } - - public static void SenderAfterThreshold(this ILogger logger, string messageId, int retries) - { - logger.LogWarning( - $"The Publisher of the message({messageId}) still fails after {retries}th sends and we will stop retrying."); - } - - public static void ExecutedThresholdCallbackFailed(this ILogger logger, Exception ex) - { - logger.LogWarning(ex, "FailedThresholdCallback action raised an exception:" + ex.Message); - } - - public static void ConsumerDuplicates(this ILogger logger, string subscriber, string group) - { - logger.LogWarning( - $"We detected that you have duplicate subscribers ({subscriber}) in same group ({group}), this will cause diversity behavior."); - } - - public static void ConsumerExecutionRetrying(this ILogger logger, string messageId, int retries) - { - logger.LogWarning($"The {retries}th retrying consume a message failed. message id: {messageId}"); - } - - public static void SenderRetrying(this ILogger logger, string messageId, int retries) - { - logger.LogWarning($"The {retries}th retrying send a message failed. message id: {messageId} "); - } - - public static void MessageReceived(this ILogger logger, string messageId, string name) - { - logger.LogDebug($"Received message. id:{messageId}, name: {name}"); - } - - public static void MessagePublishException(this ILogger logger, string? messageId, string reason, Exception? ex) - { - logger.LogError(ex, - $"An exception occurred while publishing a message, reason:{reason}. message id:{messageId}"); - } - - public static void ConsumerExecuting(this ILogger logger, string className, string methodName, string group) - { - logger.LogInformation($"Executing subscriber method '{className}.{methodName}' on group '{group}'"); - } - - public static void ConsumerExecuted(this ILogger logger, string className, string methodName, string group, - double milliseconds, string? instance) - { - logger.LogInformation( - $"Executed subscriber method '{className}.{methodName}' on group '{group}' with instance '{instance}' in {milliseconds}ms"); - } - - public static void ConsumerExecuteFailed(this ILogger logger, string topic, string id, string? instance, - Exception? ex) - { - logger.LogError(ex, - $"An exception occurred while executing the subscription method. Topic:{topic}, Id:{id}, Instance: {instance}"); - } - - public static void ServerStarting(this ILogger logger) - { - logger.LogInformation("Starting the processing server."); - } - - public static void ProcessorsStartedError(this ILogger logger, Exception ex) - { - logger.LogError(ex, "Starting the processors throw an exception."); - } - - public static void ServerShuttingDown(this ILogger logger) - { - logger.LogInformation("Shutting down the processing server..."); - } - - public static void ExpectedOperationCanceledException(this ILogger logger, Exception ex) - { - logger.LogWarning(ex, $"Expected an OperationCanceledException, but found '{ex.Message}'."); - } -} diff --git a/src/TrackCenter.Application/CAP/MySubscribeExecutor.cs b/src/TrackCenter.Application/CAP/MySubscribeExecutor.cs deleted file mode 100644 index a70f1408..00000000 --- a/src/TrackCenter.Application/CAP/MySubscribeExecutor.cs +++ /dev/null @@ -1,269 +0,0 @@ -using System.Diagnostics; -using System.Reflection; -using DotNetCore.CAP; -using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Messages; -using DotNetCore.CAP.Persistence; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using ILogger = Microsoft.Extensions.Logging.ILogger; - -namespace TrackCenter.Application.CAP; - -public class MySubscribeExecutor : ISubscribeExecutor -{ - // diagnostics listener - // ReSharper disable once InconsistentNaming - private static readonly DiagnosticListener s_diagnosticListener = - new(CapDiagnosticListenerNames.DiagnosticListenerName); - - private readonly IDataStorage _dataStorage; - private readonly string? _hostName; - private readonly ILogger _logger; - private readonly CapOptions _options; - private readonly IServiceProvider _provider; - - public MySubscribeExecutor( - ILogger logger, - IOptions options, - IServiceProvider provider) - { - _provider = provider; - _logger = logger; - _options = options.Value; - - _dataStorage = _provider.GetRequiredService(); - Invoker = _provider.GetRequiredService(); - _hostName = Helper.GetInstanceHostname(); - } - - private ISubscribeInvoker Invoker { get; } - - public async Task ExecuteAsync(MediumMessage message, ConsumerExecutorDescriptor? descriptor = null, - CancellationToken cancellationToken = default) - { - if (descriptor == null) - { - var selector = _provider.GetRequiredService(); - if (!selector.TryGetTopicExecutor(message.Origin.GetName(), message.Origin.GetGroup()!, out descriptor)) - { - var error = - $"Message (Name:{message.Origin.GetName()},Group:{message.Origin.GetGroup()}) can not be found subscriber." + - $"{Environment.NewLine} see: https://github.com/dotnetcore/CAP/issues/63"; - _logger.LogError(error); - - TracingError(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), message.Origin, null, - new Exception(error)); - - var ex = new SubscriberNotFoundException(error); - await SetFailedState(message, ex); - return OperateResult.Failed(ex); - } - } - - bool retry; - OperateResult result; - - //record instance id - message.Origin.Headers[Headers.ExecutionInstanceId] = _hostName; - - do - { - var (shouldRetry, operateResult) = await ExecuteWithoutRetryAsync(message, descriptor, cancellationToken) - .ConfigureAwait(false); - result = operateResult; - if (result.Equals(OperateResult.Success)) return result; - retry = shouldRetry; - } while (retry); - - return result; - } - - private async Task<(bool, OperateResult)> ExecuteWithoutRetryAsync(MediumMessage message, - ConsumerExecutorDescriptor descriptor, CancellationToken cancellationToken) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - cancellationToken.ThrowIfCancellationRequested(); - - try - { - _logger.ConsumerExecuting(descriptor.ImplTypeInfo.Name, descriptor.MethodInfo.Name, - descriptor.Attribute.Group); - - var sp = Stopwatch.StartNew(); - - await InvokeConsumerMethodAsync(message, descriptor, cancellationToken).ConfigureAwait(false); - - sp.Stop(); - - await SetSuccessfulState(message).ConfigureAwait(false); - - CapEventCounterSource.Log.WriteInvokeTimeMetrics(sp.Elapsed.TotalMilliseconds); - _logger.ConsumerExecuted(descriptor.ImplTypeInfo.Name, descriptor.MethodInfo.Name, - descriptor.Attribute.Group, sp.Elapsed.TotalMilliseconds, message.Origin.GetExecutionInstanceId()); - - return (false, OperateResult.Success); - } - catch (Exception ex) - { - _logger.ConsumerExecuteFailed(message.Origin.GetName(), message.DbId, - message.Origin.GetExecutionInstanceId(), ex); - - return (await SetFailedState(message, ex).ConfigureAwait(false), OperateResult.Failed(ex)); - } - } - - private Task SetSuccessfulState(MediumMessage message) - { - message.ExpiresAt = DateTime.Now.AddSeconds(_options.SucceedMessageExpiredAfter); - - return _dataStorage.ChangeReceiveStateAsync(message, StatusName.Succeeded); - } - - private async Task SetFailedState(MediumMessage message, Exception ex) - { - if (ex is SubscriberNotFoundException) - message.Retries = _options.FailedRetryCount; // not retry if SubscriberNotFoundException - - var needRetry = UpdateMessageForRetry(message); - - message.Origin.AddOrUpdateException(ex); - message.ExpiresAt = message.Added.AddSeconds(_options.FailedMessageExpiredAfter); - - await _dataStorage.ChangeReceiveStateAsync(message, StatusName.Failed).ConfigureAwait(false); - - return needRetry; - } - - private bool UpdateMessageForRetry(MediumMessage message) - { - var retries = ++message.Retries; - - if (retries == _options.FailedRetryCount) - { - try - { - _options.FailedThresholdCallback?.Invoke(new FailedInfo - { - ServiceProvider = _provider, - MessageType = MessageType.Subscribe, - Message = message.Origin - }); - - _logger.ConsumerExecutedAfterThreshold(message.DbId, _options.FailedRetryCount); - } - catch (Exception ex) - { - _logger.ExecutedThresholdCallbackFailed(ex); - } - } - - return false; - } - - private async Task InvokeConsumerMethodAsync(MediumMessage message, ConsumerExecutorDescriptor descriptor, - CancellationToken cancellationToken) - { - var consumerContext = new ConsumerContext(descriptor, message); - var tracingTimestamp = TracingBefore(message.Origin, descriptor.MethodInfo); - try - { - var ret = await Invoker.InvokeAsync(consumerContext, cancellationToken).ConfigureAwait(false); - - TracingAfter(tracingTimestamp, message.Origin, descriptor.MethodInfo); - - if (!string.IsNullOrEmpty(ret.CallbackName)) - { - var header = new Dictionary - { - [Headers.CorrelationId] = message.Origin.GetId(), - [Headers.CorrelationSequence] = (message.Origin.GetCorrelationSequence() + 1).ToString() - }; - - if (message.Origin.Headers.TryGetValue(Headers.TraceParent, out var traceparent)) - header[Headers.TraceParent] = traceparent; - - await _provider.GetRequiredService() - .PublishAsync(ret.CallbackName, ret.Result, header, cancellationToken).ConfigureAwait(false); - } - } - catch (OperationCanceledException) - { - //ignore - } - catch (Exception ex) - { - var e = new SubscriberExecutionFailedException(ex.Message, ex); - - TracingError(tracingTimestamp, message.Origin, descriptor.MethodInfo, e); - - e.ReThrow(); - } - } - - #region tracing - - private static long? TracingBefore(Message message, MethodInfo method) - { - if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.BeforeSubscriberInvoke)) - { - var eventData = new CapEventDataSubExecute - { - OperationTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), - Operation = message.GetName(), - Message = message, - MethodInfo = method - }; - - s_diagnosticListener.Write(CapDiagnosticListenerNames.BeforeSubscriberInvoke, eventData); - - return eventData.OperationTimestamp; - } - - return null; - } - - private static void TracingAfter(long? tracingTimestamp, Message message, MethodInfo method) - { - CapEventCounterSource.Log.WriteInvokeMetrics(); - if (tracingTimestamp != null && - s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.AfterSubscriberInvoke)) - { - var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - var eventData = new CapEventDataSubExecute - { - OperationTimestamp = now, - Operation = message.GetName(), - Message = message, - MethodInfo = method, - ElapsedTimeMs = now - tracingTimestamp.Value - }; - - s_diagnosticListener.Write(CapDiagnosticListenerNames.AfterSubscriberInvoke, eventData); - } - } - - private static void TracingError(long? tracingTimestamp, Message message, MethodInfo? method, Exception ex) - { - if (tracingTimestamp != null && - s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.ErrorSubscriberInvoke)) - { - var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - var eventData = new CapEventDataSubExecute - { - OperationTimestamp = now, - Operation = message.GetName(), - Message = message, - MethodInfo = method, - ElapsedTimeMs = now - tracingTimestamp.Value, - Exception = ex - }; - - s_diagnosticListener.Write(CapDiagnosticListenerNames.ErrorSubscriberInvoke, eventData); - } - } - - #endregion -} diff --git a/src/TrackCenter.Application/CAP/SubscriberExecutionFailedException.cs b/src/TrackCenter.Application/CAP/SubscriberExecutionFailedException.cs deleted file mode 100644 index a3616edc..00000000 --- a/src/TrackCenter.Application/CAP/SubscriberExecutionFailedException.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace TrackCenter.Application.CAP; - -internal sealed class SubscriberExecutionFailedException : Exception -{ - private readonly Exception _originException; - - public SubscriberExecutionFailedException(string message, Exception ex) : base(message, ex) - { - _originException = ex; - } - - public override string? StackTrace => _originException.StackTrace; - - public override string? Source => _originException.Source; -} diff --git a/src/TrackCenter.Application/Events/OrderPodPullEvent.cs b/src/TrackCenter.Application/Events/OrderPodPullEvent.cs index 3cfcf71c..3d09e256 100644 --- a/src/TrackCenter.Application/Events/OrderPodPullEvent.cs +++ b/src/TrackCenter.Application/Events/OrderPodPullEvent.cs @@ -1,6 +1,12 @@ +using Fake.EventBus.Distributed; + namespace TrackCenter.Application.Events; -public class OrderPodPullEvent +/// +/// 订单 POD 拉取(当前仓库无订阅方,仍走 Outbox 投递以兼容后续消费者)。 +/// +[Serializable] +public class OrderPodPullEvent : IntegrationEvent { // 确定应用 public string AppKey { get; set; } diff --git a/src/TrackCenter.Application/Events/TrackChangeAfterUpdateOrderEvent.cs b/src/TrackCenter.Application/Events/TrackChangeAfterUpdateOrderEvent.cs index 5259578d..e438598a 100644 --- a/src/TrackCenter.Application/Events/TrackChangeAfterUpdateOrderEvent.cs +++ b/src/TrackCenter.Application/Events/TrackChangeAfterUpdateOrderEvent.cs @@ -1,6 +1,9 @@ +using Fake.EventBus.Distributed; + namespace TrackCenter.Application.Events; -public class TrackChangeAfterUpdateOrderEvent +[Serializable] +public class TrackChangeAfterUpdateOrderEvent : IntegrationEvent { /// /// 订单Id diff --git a/src/TrackCenter.Application/Events/TrackDeleteEvent.cs b/src/TrackCenter.Application/Events/TrackDeleteEvent.cs index bb666875..8cac8130 100644 --- a/src/TrackCenter.Application/Events/TrackDeleteEvent.cs +++ b/src/TrackCenter.Application/Events/TrackDeleteEvent.cs @@ -1,8 +1,10 @@ +using Fake.EventBus.Distributed; using TrackCenter.Application.Dtos.ProvideServices; namespace TrackCenter.Application.Events; -public class TrackDeleteEvent +[Serializable] +public class TrackDeleteEvent : IntegrationEvent { /// /// 根据esId定位轨迹,优先级最高 diff --git a/src/TrackCenter.Application/Events/TrackPushEvent.cs b/src/TrackCenter.Application/Events/TrackPushEvent.cs index 001c35b4..53a63a8e 100644 --- a/src/TrackCenter.Application/Events/TrackPushEvent.cs +++ b/src/TrackCenter.Application/Events/TrackPushEvent.cs @@ -1,10 +1,13 @@ +using Fake.EventBus.Distributed; + namespace TrackCenter.Application.Events; /// /// 轨迹推送事件 /// 每次可传递多个订单,但仅能传递同一个轨迹内容 /// -public class TrackPushEvent +[Serializable] +public class TrackPushEvent : IntegrationEvent { /// /// 操作类型 diff --git a/src/TrackCenter.Application/Events/TrackUpsertEvent.cs b/src/TrackCenter.Application/Events/TrackUpsertEvent.cs index 503161c6..ee4ac79f 100644 --- a/src/TrackCenter.Application/Events/TrackUpsertEvent.cs +++ b/src/TrackCenter.Application/Events/TrackUpsertEvent.cs @@ -1,8 +1,10 @@ +using Fake.EventBus.Distributed; using TrackCenter.Application.Dtos.ProvideServices; namespace TrackCenter.Application.Events; -public class TrackUpsertEvent +[Serializable] +public class TrackUpsertEvent : IntegrationEvent { /// /// 应用 diff --git a/src/TrackCenter.Application/Events/TrackUpsertForRefreshEvent.cs b/src/TrackCenter.Application/Events/TrackUpsertForRefreshEvent.cs new file mode 100644 index 00000000..ef946ab7 --- /dev/null +++ b/src/TrackCenter.Application/Events/TrackUpsertForRefreshEvent.cs @@ -0,0 +1,9 @@ +namespace TrackCenter.Application.Events; + +/// +/// 轨迹刷新引发的新增/更新(独立队列,与 隔离)。 +/// +[Serializable] +public class TrackUpsertForRefreshEvent : TrackUpsertEvent +{ +} diff --git a/src/TrackCenter.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/TrackCenter.Application/Messaging/TrackChangeAfterUpdateOrderEventHandler.cs similarity index 93% rename from src/TrackCenter.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs rename to src/TrackCenter.Application/Messaging/TrackChangeAfterUpdateOrderEventHandler.cs index 0d801fbf..0da20f58 100644 --- a/src/TrackCenter.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/TrackCenter.Application/Messaging/TrackChangeAfterUpdateOrderEventHandler.cs @@ -1,17 +1,18 @@ -using DotNetCore.CAP; +using Fake.EventBus; +using Fake.EventBus.Distributed; using Fake.UnitOfWork; using TrackCenter.Application.Events; using TrackCenter.Application.Services.Warning.Handlers; using TrackCenter.Domain.Aggregates.OrderAggregate; -namespace TrackCenter.Application.CAP.EventHandlers; +namespace TrackCenter.Application.Messaging; public class TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository, IServiceProvider serviceProvider) - : ITransientDependency, ICapSubscribe + : IEventHandler, ITransientDependency { - [UnitOfWork] - [CapSubscribe(GlobalConst.TrackChangeAfterUpdateOrderSubscribe)] - public virtual async Task ConsumerAsync(TrackChangeAfterUpdateOrderEvent @event) + public virtual async Task HandleAsync( + TrackChangeAfterUpdateOrderEvent @event, + CancellationToken cancellationToken = default) { var orders = await GetOrdersAsync(@event.OrderIds); diff --git a/src/TrackCenter.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs b/src/TrackCenter.Application/Messaging/TrackDeleteEventHandler.cs similarity index 80% rename from src/TrackCenter.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs rename to src/TrackCenter.Application/Messaging/TrackDeleteEventHandler.cs index c3531b83..09105b19 100644 --- a/src/TrackCenter.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs +++ b/src/TrackCenter.Application/Messaging/TrackDeleteEventHandler.cs @@ -1,4 +1,5 @@ -using DotNetCore.CAP; +using Fake.EventBus; +using Fake.EventBus.Distributed; using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; using TrackCenter.Application.Dtos.ProvideServices; @@ -11,40 +12,20 @@ using TrackCenter.Domain.Aggregates.OrderAggregate; using TrackCenter.Domain.Aggregates.TrackDetailsAggregate; using TrackCenter.Repository.Aggregates.OrderAggregate; -namespace TrackCenter.Application.CAP.EventHandlers; +namespace TrackCenter.Application.Messaging; -public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe +public class TrackDeleteEventHandler( + ProvideQueries provideQueries, + IOrderRepository orderRepository, + IDistributedEventBus eventBus, + ITrackDetailsEsRepository trackDetailsEsRepository, + IOrderOperationRecordEsRepository orderOperationRecordEsRepository, + BroadcastingService broadcastingService, + WarningSignalPublisher warningSignalPublisher) + : IEventHandler, ITransientDependency { - private readonly ICapPublisher _capPublisher; - private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository; - private readonly IOrderRepository _orderRepository; - private readonly ProvideQueries _provideQueries; - private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; - private readonly BroadcastingService _broadcastingService; - private readonly WarningSignalPublisher _warningSignalPublisher; - - public TrackDeleteEventHandler( - ProvideQueries provideQueries, - IOrderRepository orderRepository, - ICapPublisher capPublisher, - ITrackDetailsEsRepository trackDetailsEsRepository, - IOrderOperationRecordEsRepository orderOperationRecordEsRepository, - BroadcastingService broadcastingService, - WarningSignalPublisher warningSignalPublisher - ) - { - _provideQueries = provideQueries; - _orderRepository = orderRepository; - _capPublisher = capPublisher; - _trackDetailsEsRepository = trackDetailsEsRepository; - _orderOperationRecordEsRepository = orderOperationRecordEsRepository; - _broadcastingService = broadcastingService; - _warningSignalPublisher = warningSignalPublisher; - } - - [UnitOfWork] - [CapSubscribe(GlobalConst.TrackDeleteSubscribe, Group = GlobalConst.TrackDeleteSubscribe)] - public virtual async Task ConsumerAsync(TrackDeleteEvent @event) + [UnitOfWork(IsTransactional = true)] + public virtual async Task HandleAsync(TrackDeleteEvent @event, CancellationToken cancellationToken = default) { if (!CanDelete(@event)) return; @@ -57,7 +38,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe private async Task DownByOrderLink(TrackDeleteEvent @event) { - var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(@event.OrderIds); + 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.AppKey)) @@ -70,7 +51,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe // 不同应用需要做内容映射 if (@event.AppKey != nextEvent.AppKey) { - var codeMaps = await _provideQueries.GetTrackCodeMapsAsync( + var codeMaps = await provideQueries.GetTrackCodeMapsAsync( @event.AppKey, nextEvent.AppKey, @event.TrackIdentifiers.Select(x => x.TrackCode).ToArray() @@ -95,7 +76,8 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe { var subEvent = nextEvent.DeepCopy(); subEvent.OrderIds = subOrderIds; - await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, subEvent); + // 关联单继续走删除链路(原 CAP 误发到 Upsert topic,此处修正) + await eventBus.PublishAsync(subEvent); } } } @@ -125,7 +107,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe // 优先根据EsId查询轨迹 if (@event.EsIds.Length > 0) { - deleteTracks = await _trackDetailsEsRepository.GetDataByIds(@event.EsIds); + deleteTracks = await trackDetailsEsRepository.GetDataByIds(@event.EsIds); // 外部api获取的轨迹不允许删除 if (deleteTracks.Any(m => m.Source == (int) TrackSourceEnum.ExternalServiceProvide)) return; @@ -143,12 +125,12 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe }).ToList(); // 查出订单下的所有轨迹,以供后面回退使用 - oldTracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds); + oldTracks = await trackDetailsEsRepository.GetListAsync(@event.OrderIds); } else { // 根据订单查询出所有的轨迹,查所有是因为主单上需要进行回退更新 - oldTracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds); + oldTracks = await trackDetailsEsRepository.GetListAsync(@event.OrderIds); // 构建轨迹标识符 var trackIds = @event.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.GetUtc0TrackTime():G}").ToHashSet(); @@ -177,7 +159,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe if (deleteTracks.Count == 0) return; // 删除轨迹批量 - await _trackDetailsEsRepository.DeleteTrackByIdsAsync(deleteTracks.Select(x => x.Id).ToHashSet()); + await trackDetailsEsRepository.DeleteTrackByIdsAsync(deleteTracks.Select(x => x.Id).ToHashSet()); // 删除轨迹后,更新订单上的轨迹信息 await TrackDeleteAfterUpdateOrderAsync(@event, oldTracks, deleteTracks, orderIds); @@ -186,13 +168,13 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe await PublicTrackTopicAsync(@event, deleteTracks); // 发布预警信号,稍后将进行预警计算 - _warningSignalPublisher.PublishSignal(WarningSignalType.轨迹删除, deleteTracks); + warningSignalPublisher.PublishSignal(WarningSignalType.轨迹删除, deleteTracks); } private async Task PublicTrackTopicAsync(TrackDeleteEvent @event, List delTracks) { var trackContentIds = delTracks.Select(x => x.TrackContentId).ToHashSet(); - var trackContents = await _provideQueries.GetTrackContentAsync(trackContentIds); + var trackContents = await provideQueries.GetTrackContentAsync(trackContentIds); var contentDict = trackContents.ToDictionary(x => x.Id); var needPublicTracks = delTracks @@ -255,7 +237,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe }; var content = contentDict[track.TrackContentId]; - _broadcastingService.TrackChangePublicTopic(eto, content.AppKey); + broadcastingService.TrackChangePublicTopic(eto, content.AppKey); } } @@ -270,7 +252,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe var deleteTrackIds = deleteTracks.Select(m => m.Id).ToList(); var newTracks = oldTracks.Where(x => !deleteTrackIds.Contains(x.Id)).ToList(); - var orders = await _orderRepository.GetListAsync(x => orderIds.Contains(x.Id), + var orders = await orderRepository.GetListAsync(x => orderIds.Contains(x.Id), x => new OrderEntity { Id = x.Id, @@ -315,7 +297,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe } //更新订单上冗余轨迹明细的字段 - await _orderRepository.UpdateRangeAsync(orders, + await orderRepository.UpdateRangeAsync(orders, x => new { x.LatestTrackStatus, @@ -329,7 +311,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe }); //批量写入订单操作日志 - _ = _orderOperationRecordEsRepository.AddManyAsync(orders.Select(order => new OrderOperationRecordIndex + _ = orderOperationRecordEsRepository.AddManyAsync(orders.Select(order => new OrderOperationRecordIndex { OrderId = order.Id, OrderNo = order.OrderNo, diff --git a/src/TrackCenter.Application/CAP/EventHandlers/TrackPushEventHandler.cs b/src/TrackCenter.Application/Messaging/TrackPushEventHandler.cs similarity index 91% rename from src/TrackCenter.Application/CAP/EventHandlers/TrackPushEventHandler.cs rename to src/TrackCenter.Application/Messaging/TrackPushEventHandler.cs index c9c8f06c..206796f1 100644 --- a/src/TrackCenter.Application/CAP/EventHandlers/TrackPushEventHandler.cs +++ b/src/TrackCenter.Application/Messaging/TrackPushEventHandler.cs @@ -1,6 +1,7 @@ using System.Collections.Immutable; using System.Text.Json; -using DotNetCore.CAP; +using Fake.EventBus; +using Fake.EventBus.Distributed; using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; using Microsoft.Extensions.Options; @@ -18,48 +19,28 @@ using TrackCenter.Domain.Aggregates.TrackDetailsAggregate; using TrackCenter.Domain.Aggregates.TrackPushAggregate; using TrackCenter.Repository.Otel; -namespace TrackCenter.Application.CAP.EventHandlers; +namespace TrackCenter.Application.Messaging; -public class TrackPushEventHandler : ITransientDependency, ICapSubscribe +public class TrackPushEventHandler( + IOrderRepository orderRepository, + TrackPushCacheService trackPushCacheService, + ITrackPushRecordEsRepository trackPushRecordEsRepository, + IOptionsMonitor options, + BroadcastingService broadcastingService, + ITrackDetailsEsRepository trackDetailsEsRepository, + InterfaceForwardService interfaceForwardService) + : IEventHandler, ITransientDependency { - private readonly IOptionsMonitor _options; - private readonly IOrderRepository _orderRepository; - private readonly TrackPushCacheService _trackPushCacheService; - private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository; - private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; - private readonly InterfaceForwardService _interfaceForwardService; - private readonly BroadcastingService _broadcastingService; private List _orders = null!; private List _pushConfigs = null!; private Dictionary> _orderTypeSortedConfigsDict = null!; //订单类型,根据sort从小到大排序后的配置字典 - public TrackPushEventHandler( - IOrderRepository orderRepository, - TrackPushCacheService trackPushCacheService, - ITrackPushRecordEsRepository trackPushRecordEsRepository, - IOptionsMonitor options, - BroadcastingService broadcastingService, - ITrackDetailsEsRepository trackDetailsEsRepository, - InterfaceForwardService interfaceForwardService) - { - _orderRepository = orderRepository; - _trackPushCacheService = trackPushCacheService; - _trackPushRecordEsRepository = trackPushRecordEsRepository; - _options = options; - _broadcastingService = broadcastingService; - _trackDetailsEsRepository = trackDetailsEsRepository; - _interfaceForwardService = interfaceForwardService; - } - - [UnitOfWork] - [CapSubscribe(GlobalConst.TrackPushSubscribe, Group = GlobalConst.TrackPushSubscribe)] - [CapSubscribe(GlobalConst.TrackManualPushSubscribe, Group = GlobalConst.TrackPushSubscribe)] - public virtual async Task ConsumerAsync(TrackPushEvent @event) + public virtual async Task HandleAsync(TrackPushEvent @event, CancellationToken cancellationToken = default) { // 应用+客户id找推送映射配置 - var pushConfigs = await _trackPushCacheService.GetPushContentConfigsAsync(@event.AppKey, @event.Customer); + var pushConfigs = await trackPushCacheService.GetPushContentConfigsAsync(@event.AppKey, @event.Customer); if (pushConfigs == null || pushConfigs.Count == 0) return; if (pushConfigs.First().ServiceProviderCode.IsNullOrWhiteSpace()) { @@ -75,7 +56,7 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe // 查找所有订单 var orderIds = @event.OrderIdTrackMetadataDict.Keys.ToHashSet(); - var orders = await _orderRepository.GetListAsync(x => orderIds.Contains(x.Id), x => + var orders = await orderRepository.GetListAsync(x => orderIds.Contains(x.Id), x => new OrderEntity { Id = x.Id, @@ -134,8 +115,8 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe { var asciiString = Base64Helper.SerializeObject(OptionType.新增.ToString()); var serviceProviderCode = _pushConfigs.First().ServiceProviderCode; - var r = await _interfaceForwardService.BatchForwardThenPushToQueueAsync( - _options.CurrentValue.PushTrackInterfaceCode, + var r = await interfaceForwardService.BatchForwardThenPushToQueueAsync( + options.CurrentValue.PushTrackInterfaceCode, serviceProviderCode, items.Cast().ToList(), GlobalConst.TrackPushCompletedSubscribe, @@ -369,8 +350,8 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe { var asciiString = Base64Helper.SerializeObject(OptionType.修改.ToString()); var serviceProviderCode = _pushConfigs.First().ServiceProviderCode; - var r = await _interfaceForwardService.BatchForwardThenPushToQueueAsync( - _options.CurrentValue.TrackUpdateInterfaceCode, + var r = await interfaceForwardService.BatchForwardThenPushToQueueAsync( + options.CurrentValue.TrackUpdateInterfaceCode, serviceProviderCode, items.Cast().ToList(), GlobalConst.TrackPushCompletedSubscribe, @@ -448,13 +429,13 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe if (config.IsAllPush) { - var history = await _trackPushRecordEsRepository.GetLatestTrackPushRecordAsync(log.OrderId, true); + var history = await trackPushRecordEsRepository.GetLatestTrackPushRecordAsync(log.OrderId, true); if (history != null) { body = TextJsonHelper.Deserialize(history.PushContent); //在推送历史中,选出当前轨迹明细一致的轨迹 - var tracks = await _trackDetailsEsRepository.GetListAsync(log.OrderId); + var tracks = await trackDetailsEsRepository.GetListAsync(log.OrderId); //确定轨迹标识符 var trackIdentifies = tracks.Select(x => { @@ -619,7 +600,7 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe { using var activity = ActivityHelper.CreateSpanActivity($"TrackPushFailedPublicTopic-{order.OrderNo}"); activity.SetTag("failedMessage", failedMessage); - _broadcastingService.TrackPushFailedPubilcTopic(new TrackPushRecordDto + broadcastingService.TrackPushFailedPubilcTopic(new TrackPushRecordDto { AppKey = @event.AppKey, IsManualPush = @event.OperationMan != null, @@ -656,7 +637,7 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe activity.SetTag("@event", @event.ToJson()); foreach (var pushInput in pushOrUpdateInputs) { - _broadcastingService.TrackPushFailedPubilcTopic(new TrackPushRecordDto + broadcastingService.TrackPushFailedPubilcTopic(new TrackPushRecordDto { AppKey = @event.AppKey, IsManualPush = @event.OperationMan != null, diff --git a/src/TrackCenter.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/TrackCenter.Application/Messaging/TrackUpsertEventHandler.cs similarity index 71% rename from src/TrackCenter.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs rename to src/TrackCenter.Application/Messaging/TrackUpsertEventHandler.cs index d491de7a..461d37eb 100644 --- a/src/TrackCenter.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/TrackCenter.Application/Messaging/TrackUpsertEventHandler.cs @@ -1,4 +1,5 @@ -using DotNetCore.CAP; +using Fake.EventBus; +using Fake.EventBus.Distributed; using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; using TrackCenter.Application.Events; @@ -13,41 +14,36 @@ using TrackCenter.Repository.Aggregates.OrderAggregate; using TrackCenter.Repository.Otel; using OrderIdentifier = TrackCenter.Application.Events.OrderIdentifier; -namespace TrackCenter.Application.CAP.EventHandlers; +namespace TrackCenter.Application.Messaging; -public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe +public class TrackUpsertEventHandler( + IOrderRepository orderRepository, + IDistributedEventBus eventBus, + ProvideQueries provideQueries, + ITrackDetailsEsRepository trackDetailsEsRepository, + IOrderOperationRecordEsRepository orderOperationRecordEsRepository, + BroadcastingService broadcastingService, + WarningSignalPublisher warningSignalPublisher) + : + IEventHandler, + IEventHandler, + ITransientDependency { - private readonly ICapPublisher _capPublisher; - private readonly IOrderRepository _orderRepository; - private readonly ProvideQueries _provideQueries; - private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; - private readonly BroadcastingService _broadcastingService; - private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository; - private readonly WarningSignalPublisher _warningSignalPublisher; + Task IEventHandler.HandleAsync(Event eventData, CancellationToken cancellationToken) + => eventData switch + { + TrackUpsertForRefreshEvent refresh => HandleAsync(refresh, cancellationToken), + TrackUpsertEvent upsert => HandleAsync(upsert, cancellationToken), + _ => Task.CompletedTask + }; - public TrackUpsertEventHandler( - IOrderRepository orderRepository, - ICapPublisher capPublisher, - ProvideQueries provideQueries, - ITrackDetailsEsRepository trackDetailsEsRepository, - IOrderOperationRecordEsRepository orderOperationRecordEsRepository, - BroadcastingService broadcastingService, - WarningSignalPublisher warningSignalPublisher - ) - { - _orderRepository = orderRepository; - _capPublisher = capPublisher; - _provideQueries = provideQueries; - _trackDetailsEsRepository = trackDetailsEsRepository; - _orderOperationRecordEsRepository = orderOperationRecordEsRepository; - _broadcastingService = broadcastingService; - _warningSignalPublisher = warningSignalPublisher; - } + public Task HandleAsync(TrackUpsertEvent @event, CancellationToken cancellationToken = default) + => ConsumerAsync(@event); - [UnitOfWork] - [CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)] - [CapSubscribe(GlobalConst.TrackUpsertForRefreshSubscribe, Group = GlobalConst.TrackUpsertForRefreshSubscribe)] - public virtual async Task ConsumerAsync(TrackUpsertEvent @event) + public Task HandleAsync(TrackUpsertForRefreshEvent @event, CancellationToken cancellationToken = default) + => ConsumerAsync(@event); + + private async Task ConsumerAsync(TrackUpsertEvent @event) { if (!CanDelete(@event)) return; @@ -56,22 +52,22 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe await HandleTrackAsync(@event, canNextOrderIds); if (canNextOrderIds.Count == 0) return; - // ????????????????? + // 根据订单关联关系异步向下刷(异步) await DownByOrderLink(@event, canNextOrderIds); } private async Task DownByOrderLink(TrackUpsertEvent @event, List canNextOrderIds) { - // ????????????????? - var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(canNextOrderIds.ToArray()); + // 根据订单关联关系异步向下刷(异步) + var linkedOrders = await orderRepository.GetLinkedOrdersAsync(canNextOrderIds.ToArray()); foreach (var order in @event.OrderIdentifiers) { - // ??????????? + // 理论上小包在这不会分组 foreach (var group in linkedOrders.Where(x => x.OwnerOrderId == order.OrderId) .GroupBy(x => new { x.AppKey, - x.Customer // ????????????????? + x.Customer // 这里按客户分组是为了后续的推送方便 })) { var nextEvent = @event.DeepCopy(); @@ -85,15 +81,15 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe OriginTrackDataHash = @event.TrackRefreshData.OriginTrackDataHash, }; - // ??????????? + // 不同应用需要做内容映射 if (@event.AppKey != nextEvent.AppKey) { - var mapCode = (await _provideQueries.MapTrackCodesAsync(@event.AppKey, nextEvent.AppKey, @event.TrackCode)) + var mapCode = (await provideQueries.MapTrackCodesAsync(@event.AppKey, nextEvent.AppKey, @event.TrackCode)) .FirstOrDefault(); if (mapCode == null) { - // ????????????? + // 跨应用没做映射的轨迹不处理 continue; } @@ -111,7 +107,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe { var subEvent = nextEvent.DeepCopy(); subEvent.OrderIdentifiers = subOrderIds.ToArray(); - await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, subEvent); + await eventBus.PublishAsync(subEvent); } } } @@ -119,10 +115,10 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe private static bool CanDelete(TrackUpsertEvent @event) { - // ???????????? + // 系统创建的轨迹不允许修改 if (@event.Visited.IsNullOrEmpty() && @event is { OperationMan: GlobalConst.SystemUser, IsAdd: false }) { - Log.Warning($"??????????????{@event}", true); + Log.Warning($"系统创建的轨迹不允许被修改:{@event}", true); return false; } @@ -131,7 +127,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe var dup = @event.Visited.Intersect(orderIds).ToArray(); if (dup.Any()) { - Log.Warning($"{(@event.IsAdd ? "??" : "??")}???????????{dup.JoinAsString(",")}", true); + Log.Warning($"{(@event.IsAdd ? "添加" : "修改")}轨迹时,发现循环依赖:{dup.JoinAsString(",")}", true); return false; } @@ -140,29 +136,29 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe private async Task HandleTrackAsync(TrackUpsertEvent @event, List canNextOrderIds) { - //#7001:?????????????????????????????????????? - var trackContent = await _provideQueries.GetTrackContentAsync(@event.AppKey, @event.TrackCode); + //#7001:未来潜在需求,当轨迹内容匹配预设,记录一个标记,保证下刷过程都是使用预设内容 + var trackContent = await provideQueries.GetTrackContentAsync(@event.AppKey, @event.TrackCode); if (trackContent == null) { - // ???????????? - Log.Warning($"????????{@event}", true); + // 找不到轨迹内容,直接结束 + Log.Warning($"找不到轨迹内容:{@event}", true); return; } - // ??????????????? + // 根据轨迹内容标识,确定操作权限 var manualOperation = @event.Source == (int) TrackSourceEnum.Artificial; - // ??????? + // 不允许手动创建 if (manualOperation && @event.IsAdd && trackContent.IsAllowManuallyCreate == false) { - PublicTopicAllFailed(@event, trackContent, "?????????????"); + PublicTopicAllFailed(@event, trackContent, "轨迹内容标识不允许手动创建"); return; } - // ??????? + // 不允许手动更新 if (manualOperation && !@event.IsAdd && trackContent.IsAllowManuallyUpdate == false) { - PublicTopicAllFailed(@event, trackContent, "?????????????"); + PublicTopicAllFailed(@event, trackContent, "轨迹标识内容不允许手动更新"); return; } @@ -181,30 +177,30 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe if (insertTracks.Any()) { - // ??add to es tips:?????????? - await _trackDetailsEsRepository.AddManyAsync(insertTracks); + // 批量add to es tips:注意副作用填充版本号 + await trackDetailsEsRepository.AddManyAsync(insertTracks); - // es?????????? + // es新增后填充版本号字典 insertTracks.ForEach(t => orderIdTrackMetadataDict.Add(t.OrderId, TrackMetadata.Build(t.Id, t.Version, t.CreateTime))); - //?????????? - _ = _orderOperationRecordEsRepository.AddManyAsync(insertTracks.Select(t => BuildOrderOperationRecord(@event, t, new OrderIdentifier + // 批量写入订单操作日志 + _ = orderOperationRecordEsRepository.AddManyAsync(insertTracks.Select(t => BuildOrderOperationRecord(@event, t, new OrderIdentifier { OrderNo = t.OrderNo, OrderId = t.OrderId })).ToList()); - // ?????????????? - await _orderRepository.UpdatePullStatusToSilenceAsync(insertTracks.Select(x => x.OrderId).ToList(), + // 添加轨迹触发订单拉取状态更新 + await orderRepository.UpdatePullStatusToSilenceAsync(insertTracks.Select(x => x.OrderId).ToList(), @event.TrackCode); - // ???????????????? - _warningSignalPublisher.PublishSignal(WarningSignalType.轨迹新增, insertTracks); + // 发布预警信号,稍后将进行预警计算 + warningSignalPublisher.PublishSignal(WarningSignalType.轨迹新增, insertTracks); - // ??????????????pod?? + // 如果存在轨迹标记,则触发订单pod拉取 if (!string.IsNullOrWhiteSpace(trackContent.TrackFlagId)) { - await _capPublisher.PublishAsync(GlobalConst.OrderPodPullSubscribe, new OrderPodPullEvent + await eventBus.PublishAsync(new OrderPodPullEvent { AppKey = @event.AppKey, OrderIdEsIdDict = insertTracks.ToDictionary(x => x.OrderId, y => y.Id), @@ -213,25 +209,24 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe } } - // ???????? + // 触发轨迹变更广播 await TrackChangePublicTopicAsync(trackContent, trackChangeEtos, true); - // ?????????????? - await _capPublisher.PublishAsync(GlobalConst.TrackChangeAfterUpdateOrderSubscribe, - new TrackChangeAfterUpdateOrderEvent - { - OrderIds = canNextOrderIds.ToArray(), - IsCompleted = trackContent.IsCompleted, - TrackStatus = trackContent.TrackStatus, - TrackContent = trackContent.TrackContent, - TrackEnContent = trackContent.TrackEnContent, - TrackPlace = @event.TrackPlace, - TrackTime = @event.TrackTime, - TrackTimeZone = @event.TrackTimeZone, - }); + // 触发订单主表更新事件(异步) + await eventBus.PublishAsync(new TrackChangeAfterUpdateOrderEvent + { + OrderIds = canNextOrderIds.ToArray(), + IsCompleted = trackContent.IsCompleted, + TrackStatus = trackContent.TrackStatus, + TrackContent = trackContent.TrackContent, + TrackEnContent = trackContent.TrackEnContent, + TrackPlace = @event.TrackPlace, + TrackTime = @event.TrackTime, + TrackTimeZone = @event.TrackTimeZone, + }); // 触发轨迹推送事件(异步) - // tips:???????????????? + // tips:同一个轨迹内容,多个订单多条轨迹 var trackPushEvent = new TrackPushEvent { OptionType = @event.IsAdd ? OptionType.新增 : OptionType.修改, @@ -253,7 +248,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe ForcedPush = @event.ForcedPush, IsToMq = (trackContent.IsToMq || @event.IsToMq) }; - await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, trackPushEvent); + await eventBus.PublishAsync(trackPushEvent); } private async Task> UpsertTrackAsync( @@ -267,7 +262,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray(); // important:轨迹code相同,时间、发生地不同的,可能存在多条!! - var tracks = await _trackDetailsEsRepository.GetListAsync(orderIds, @event.TrackCode, true); + var tracks = await trackDetailsEsRepository.GetListAsync(orderIds, @event.TrackCode, true); var insertTracks = new List(); var updateTracks = new List(); @@ -290,7 +285,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe } else { - var message = $"???????EsId:[{@event.EsId}]????????????"; + var message = $"没有通过传入的EsId:[{@event.EsId}]查询到轨迹信息,更新失败"; AddTrackChangeEto(trackChangeEtos, @event, trackContent, order.OrderNo, null, message); } @@ -299,21 +294,21 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe var existTracks = tracks.Where(x => x.OrderId == order.OrderId).ToList(); - // tips:??????????8?????? + // tips:如果没传时区则使用+8兜底进行过滤 var timezone = Math.Abs(@event.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 0.01f ? 8.0f : @event.TrackTimeZone; - // ?????? + // 根据时间过滤 existTracks = existTracks.Where(x => x.GetUtc0TrackTime() == @event.TrackTime.Subtract(TimeSpan.FromHours(timezone))).ToList(); - // ???????? + // 根据扩展信息过滤 existTracks = existTracks.Where(x => x.Extra == @event.Extra).ToList(); if (@event.IsAdd) { if (existTracks.Count > 0) { - const string message = "??????????????????????"; + const string message = "订单已经存在不允许重复的轨迹,不允许重复添加"; traceLog.Add($"OrderNo-{order.OrderNo}", message); AddTrackChangeEto(trackChangeEtos, @event, trackContent, order.OrderNo, null, message); continue; @@ -325,10 +320,10 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe } else { - // ?????? + // 不存在不让改 if (existTracks.Count == 0) { - const string message = "?????????????"; + const string message = "订单不存在轨迹,不允许修改"; traceLog.Add($"OrderNo-{order.OrderNo}", message); AddTrackChangeEto(trackChangeEtos, @event, trackContent, order.OrderNo, null, message); continue; @@ -336,7 +331,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe if (existTracks.Count > 1) { - const string message = "?????????????"; + const string message = "订单存在多条轨迹不允许修改"; traceLog.Add($"OrderNo-{order.OrderNo}", message); AddTrackChangeEto(trackChangeEtos, @event, trackContent, order.OrderNo, null, message); continue; @@ -356,22 +351,22 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe if (updateTracks.Any()) { - // ????????? - await _trackDetailsEsRepository.BulkUpdateAsync(updateTracks); - // ???????? updateTracks.ForEach(x => orderIdTrackMetadataDict.Add(x.OrderId, TrackMetadata.Build(x.Id, x.Version, x.CreateTime))); - // ???????? - _ = _orderOperationRecordEsRepository.AddManyAsync(operationRecords); - // ??????????????? - _warningSignalPublisher.PublishSignal(WarningSignalType.轨迹更新, tracks); + // 批量差异化更新轨迹 + await trackDetailsEsRepository.BulkUpdateAsync(updateTracks); + // 填充轨迹元数据 + updateTracks.ForEach(x => orderIdTrackMetadataDict.Add(x.OrderId, TrackMetadata.Build(x.Id, x.Version, x.CreateTime))); + // 批量写入操作日志 + _ = orderOperationRecordEsRepository.AddManyAsync(operationRecords); + // 发布预警信号稍后将进行预警计算 + warningSignalPublisher.PublishSignal(WarningSignalType.轨迹更新, tracks); } return insertTracks; } - private static TrackDetailsIndex BuiltUpdateTrack(TrackUpsertEvent @event, TrackDetailsIndex track, OrderIdentifier order, TrackContentVO trackContent) { - // ?????????? ????????????? + // 非外部轨迹才允许修改 【发生地】【时间】【时区】 if (track.Source != (int) TrackSourceEnum.ExternalServiceProvide) { track.TrackPlace = @event.TrackPlace; @@ -379,11 +374,11 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe track.TrackTimeZone = @event.TrackTimeZone; } - //?????????? + // 允许二次修改轨迹内容 track.TrackContent = string.IsNullOrWhiteSpace(@event.Content) ? trackContent.TrackContent : @event.Content; track.TrackEnContent = string.IsNullOrWhiteSpace(@event.EnStatus) ? trackContent.TrackEnContent : @event.EnStatus; - // ?????????? + // 轨迹发生地的更多信息 track.TrackPlaceCity = GlobalConst.EmptyString; track.TrackPlaceCityId = GlobalConst.NotExistId; track.TrackPlaceProvince = GlobalConst.EmptyString; @@ -392,16 +387,16 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe track.TrackPlaceNationId = GlobalConst.NotExistId; track.TrackPlacePostcode = GlobalConst.EmptyString; - // ?????????????????????? + // 签收地时区,签收地时间 track.DestinationTimeZone = null; track.EstimatedDeliveryDate = null; - // ???utc0??? + // 转换为utc0的时间 track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1 ? track.TrackTime : track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone)); - // ????ids???????????????? + // 轨迹标记ids,是否对外,备注,扩展信息,附件 track.TrackFlagIds = trackContent.TrackFlagId; track.IsExternal = @event.IsExternal ?? trackContent.IsExternal; track.Remarks = @event.Remarks ?? GlobalConst.EmptyString; @@ -412,8 +407,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe FileName = x.FileName }).ToList(); - - // ???? + // 审计属性 track.UpdateUser = @event.OperationMan ?? GlobalConst.SystemUser; track.UpdateTime = DateTime.Now; @@ -424,13 +418,13 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe { var track = new TrackDetailsIndex { - // ???? + // 订单信息 AppKey = @event.AppKey, OrderId = order.OrderId, OrderNo = order.OrderNo, OrderType = order.OrderType, - // ???? + // 轨迹信息 TrackCode = @event.TrackCode, TrackContentId = trackContent.TrackContentId, TrackContent = string.IsNullOrWhiteSpace(@event.Content) ? trackContent.TrackContent : @event.Content, @@ -442,12 +436,12 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe TrackTimeZone = @event.TrackTimeZone, TrackPlace = @event.TrackPlace, - // ??????? + // 服务商轨迹信息 ServiceProviderCode = @event.TrackRefreshData.ServiceProviderCode ?? GlobalConst.EmptyString, OriginTrackContent = @event.TrackRefreshData.OriginTrackContent ?? GlobalConst.EmptyString, OriginTrackDataHash = @event.TrackRefreshData.OriginTrackDataHash ?? GlobalConst.EmptyString, - // ?????????? + // 轨迹发生地的更多描述 TrackPlaceCity = GlobalConst.EmptyString, TrackPlaceCityId = GlobalConst.NotExistId, TrackPlaceProvince = GlobalConst.EmptyString, @@ -455,7 +449,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe TrackPlaceNation = GlobalConst.EmptyString, TrackPlaceNationId = GlobalConst.NotExistId, TrackPlacePostcode = GlobalConst.EmptyString, - // ????ids????????????????????? + // 轨迹标记ids,轨迹来源,是否对外,备注,扩展信息,附件 TrackFlagIds = trackContent.TrackFlagId, Source = @event.Source, IsExternal = @event.IsExternal ?? trackContent.IsExternal, @@ -467,12 +461,12 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe FileName = x.FileName }).ToList(), - // ???? + // 审计属性 CreateUser = @event.OperationMan ?? GlobalConst.SystemUser, CreateTime = DateTime.Now }; - // ???utc0??? + // 转换为utc0的时间 track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1 ? track.TrackTime : track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone)); @@ -497,15 +491,17 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe private async Task TrackChangePublicTopicAsync(TrackContentVO trackContent, List list, bool isDelay = false) { if (list.Count == 0) return; - //??????????s????https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-refresh.html - //????????????????? - //?????????? - //??1??!???????????????????????????? //??2?????????es???????? //??3???????????????? + // 理想情况在写入之后1s会刷盘 https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-refresh.html + // 增加一个版本号来确定是否真的变更了 + // 没有刷盘成功事件回调 + // 方案1:!!【轮询等待静默刷盘】查出版本号确实发生了变更在发送广播 + // 方案2:考虑强制刷盘(对es压力大)后发送 + // 方案3:采用一个较大延时,不查询直接发 if (isDelay) await Task.Delay(1000); foreach (var eto in list) - _broadcastingService.TrackChangePublicTopic(eto, trackContent.AppKey); + broadcastingService.TrackChangePublicTopic(eto, trackContent.AppKey); } private void PublicTopicAllFailed(TrackUpsertEvent @event, TrackContentVO trackContent, string failedReason) @@ -514,7 +510,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe foreach (var orderNo in @event.OrderIdentifiers.Select(x => x.OrderNo)) { var eto = BuildEto(@event, trackContent, orderNo, null, failedReason); - _broadcastingService.TrackChangePublicTopic(eto, trackContent.AppKey); + broadcastingService.TrackChangePublicTopic(eto, trackContent.AppKey); } } diff --git a/src/TrackCenter.Application/Rabbit/TrackPushCompletedEventHandler.cs b/src/TrackCenter.Application/Rabbit/TrackPushCompletedEventHandler.cs index aabd805c..5c1ed968 100644 --- a/src/TrackCenter.Application/Rabbit/TrackPushCompletedEventHandler.cs +++ b/src/TrackCenter.Application/Rabbit/TrackPushCompletedEventHandler.cs @@ -34,7 +34,7 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl return options.Queue.StartsWith(GlobalConst.TrackPushCompletedSubscribe); } - [UnitOfWork] + [UnitOfWork(IsTransactional = true)] public virtual async Task Handle(BasicDeliverEventArgs args) { var msg = string.Empty; diff --git a/src/TrackCenter.Application/Rabbit/TrackRefreshEventHandler.cs b/src/TrackCenter.Application/Rabbit/TrackRefreshEventHandler.cs index c74258d8..ade732fe 100644 --- a/src/TrackCenter.Application/Rabbit/TrackRefreshEventHandler.cs +++ b/src/TrackCenter.Application/Rabbit/TrackRefreshEventHandler.cs @@ -1,6 +1,6 @@ using System.Diagnostics; using System.Text; -using DotNetCore.CAP; +using Fake.EventBus.Distributed; using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; using Microsoft.Extensions.Logging; @@ -21,7 +21,7 @@ namespace TrackCenter.Application.Rabbit; [ExposeServices(typeof(IRabbitHandler))] public class TrackRefreshEventHandler( IOrderRepository orderRepository, - ICapPublisher capPublisher, + IDistributedEventBus eventBus, TrackPullCacheService trackPullCacheService, ITrackDetailsEsRepository trackDetailsEsRepository, ILogger logger, @@ -33,7 +33,7 @@ public class TrackRefreshEventHandler( return coptions.Queue.StartsWith(GlobalConst.TrackRefreshSubscribe); } - [UnitOfWork] + [UnitOfWork(IsTransactional = true)] public virtual async Task Handle(BasicDeliverEventArgs args) { var msg = string.Empty; @@ -252,7 +252,7 @@ public class TrackRefreshEventHandler( } // 新增/更新轨迹 - var trackUpsertEvent = new TrackUpsertEvent + var trackUpsertEvent = new TrackUpsertForRefreshEvent { OrderIdentifiers = new[] @@ -284,7 +284,7 @@ public class TrackRefreshEventHandler( Extra = trackExtra }; - await capPublisher.PublishAsync(GlobalConst.TrackUpsertForRefreshSubscribe, trackUpsertEvent); + await eventBus.PublishAsync(trackUpsertEvent); } private async Task InsertNotMappedTrackAsync(JToken trackToken, TrackRefreshContext context, string? trackPlace, diff --git a/src/TrackCenter.Application/Services/ProvideServices/OrderService.Link.cs b/src/TrackCenter.Application/Services/ProvideServices/OrderService.Link.cs index 255dbbfb..3371500e 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/OrderService.Link.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/OrderService.Link.cs @@ -1,4 +1,6 @@ -using DotNetCore.CAP; +using System.Data; +using Fake.EventBus.Distributed; +using Fake.UnitOfWork; using TrackCenter.Application.Dtos.ProvideServices; using TrackCenter.Application.Events; using TrackCenter.Domain.Aggregates.OrderAggregate; @@ -11,8 +13,8 @@ namespace TrackCenter.Application.Services.ProvideServices; /// public partial class OrderService { - private readonly ICapPublisher _capPublisher; - private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; + private readonly IDistributedEventBus _eventBus = eventBus; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository = trackDetailsEsRepository; /// /// 关联、解除关联订单 @@ -21,9 +23,10 @@ public partial class OrderService /// /// [HttpPost("Order/Link")] - public async Task LinkOrderAsync(LinkOrderInput input) + [UnitOfWork(IsTransactional = true, IsolationLevel = IsolationLevel.ReadCommitted)] + public virtual async Task LinkOrderAsync(LinkOrderInput input) { - var orderId = await _orderRepository.GetFirstAsync(x => + var orderId = await orderRepository.GetFirstAsync(x => x.AppKey == input.AppKey && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => x.Id); if (orderId == default) @@ -60,13 +63,13 @@ public partial class OrderService { // 获取已关联的订单 var linkOrderNos = - await _orderRepository.GetLinkedOrdersAsync(orderId, input.LinkAppKey, input.LinkOrderType); + await orderRepository.GetLinkedOrdersAsync(orderId, input.LinkAppKey, input.LinkOrderType); // 计算出未关联的订单 var noLinkOrderNos = input.LinkOrderNos.Except(linkOrderNos).ToList(); // 查询存在的订单 - var existedOrders = await _orderRepository.GetListAsync(x => + var existedOrders = await orderRepository.GetListAsync(x => x.AppKey == input.LinkAppKey && x.OrderType == input.LinkOrderType && noLinkOrderNos.Contains(x.OrderNo), x => new @@ -90,7 +93,7 @@ public partial class OrderService return 0; } - await _orderRepository.LinkOrderAsync(existedOrders.Select(x => new OrderLinkEntity + await orderRepository.LinkOrderAsync(existedOrders.Select(x => new OrderLinkEntity { OrderId = orderId, LinkOrderId = x.Id, @@ -127,7 +130,7 @@ public partial class OrderService IsAdd = true // 存在则不新增 }; - await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, fillTrackEvent); + await _eventBus.PublishAsync(fillTrackEvent); } } @@ -136,11 +139,11 @@ public partial class OrderService private async Task UnLinkOrderAsync(LinkOrderInput input, int orderId) { - var unLinkIds = await _orderRepository.GetLinkedOrdersAsync(orderId, input.LinkAppKey, input.LinkOrderType, + var unLinkIds = await orderRepository.GetLinkedOrdersAsync(orderId, input.LinkAppKey, input.LinkOrderType, input.LinkOrderNos); // real del - await _orderRepository.UnLinkByIdsAsync(unLinkIds); + await orderRepository.UnLinkByIdsAsync(unLinkIds); return unLinkIds.Count; } } diff --git a/src/TrackCenter.Application/Services/ProvideServices/OrderService.PullConfigs.cs b/src/TrackCenter.Application/Services/ProvideServices/OrderService.PullConfigs.cs index 85bc64a0..4f421f0d 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/OrderService.PullConfigs.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/OrderService.PullConfigs.cs @@ -23,7 +23,7 @@ public partial class OrderService return new FindOrderPullConfigsOutput(); } - var pullConfigs = await _orderRepository.FindOrderPullConfigsAsync(input.AppKey, input.OrderType, orderNos); + var pullConfigs = await orderRepository.FindOrderPullConfigsAsync(input.AppKey, input.OrderType, orderNos); var foundOrderNos = pullConfigs .Select(x => x.OrderNo) .Distinct() @@ -57,7 +57,7 @@ public partial class OrderService [HttpPost("Order/UpdateOrderPullConfigs")] public async Task UpdateOrderPullConfigsAsync(UpdateOrderPullConfigsInput input) { - var orderIds = await _orderRepository.GetListAsync( + var orderIds = await orderRepository.GetListAsync( x => x.AppKey == input.AppKey && x.OrderType == input.OrderType && input.OrderNos.Contains(x.OrderNo), x => x.Id); @@ -69,7 +69,7 @@ public partial class OrderService var inputVo = ObjectMapper .Map(input.Config); inputVo.OrderIds = orderIds.ToArray(); - var cnt = await _orderRepository.UpdateOrderPullConfigForServiceProviderAsync(inputVo); + var cnt = await orderRepository.UpdateOrderPullConfigForServiceProviderAsync(inputVo); Log.Warning( $"{CurrentUser.UserName}正在修改服务商拉取信息,本次共计影响了{orderIds.Count}个订单、{cnt}段拉取,请求参数是:{input.ToJson()}", diff --git a/src/TrackCenter.Application/Services/ProvideServices/OrderService.V2.cs b/src/TrackCenter.Application/Services/ProvideServices/OrderService.V2.cs index af38574f..992449be 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/OrderService.V2.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/OrderService.V2.cs @@ -19,7 +19,7 @@ public partial class OrderService [VerifySignature] public async Task UpsertSmallBagAsync(UpsertSmallBagInput input) { - var order = await _orderRepository.GetFirstAsync(x => + var order = await orderRepository.GetFirstAsync(x => x.AppKey == AppKey && x.OrderType == TrackOrderType.小包 && x.OrderNo == input.OrderNo); if (order != null) { @@ -27,7 +27,7 @@ public partial class OrderService order = await BuiltOrder(input); ApplyUpsertOntoExisting(order, existing, resetTrackInfoWhenTrackNoChanged: true); - await _orderRepository.UpdateOrderAsync(order); + await orderRepository.UpdateOrderAsync(order); var index = new OrderOperationRecordIndex { @@ -39,13 +39,13 @@ public partial class OrderService CreateUserName = CurrentUser.UserName ?? string.Empty, }; - _ = _orderOperationRecordEsRepository.AddAsync(index); + _ = orderOperationRecordEsRepository.AddAsync(index); return new IdBaseDto { Id = order.Id }; } order = await BuiltOrder(input); - var orderId = await _orderRepository.CreateOrderAsync(order); + var orderId = await orderRepository.CreateOrderAsync(order); var indexForAdd = new OrderOperationRecordIndex { @@ -57,7 +57,7 @@ public partial class OrderService CreateUserName = CurrentUser.UserName ?? string.Empty, CreateTime = DateTime.Now }; - _ = _orderOperationRecordEsRepository.AddAsync(indexForAdd); + _ = orderOperationRecordEsRepository.AddAsync(indexForAdd); return new IdBaseDto { Id = orderId }; } @@ -69,7 +69,7 @@ public partial class OrderService [VerifySignature] public async Task UpsertBigBagAsync(UpsertBigBagInput input) { - var order = await _orderRepository.GetFirstAsync(x => + var order = await orderRepository.GetFirstAsync(x => x.AppKey == AppKey && x.OrderType == TrackOrderType.大包 && x.OrderNo == input.BagNo); if (order != null) { @@ -77,7 +77,7 @@ public partial class OrderService order = await BuiltOrder(input); ApplyUpsertOntoExisting(order, existing, resetTrackInfoWhenTrackNoChanged: false); - await _orderRepository.UpdateOrderAsync(order); + await orderRepository.UpdateOrderAsync(order); var index = new OrderOperationRecordIndex { @@ -89,13 +89,13 @@ public partial class OrderService CreateUserName = CurrentUser.UserName ?? string.Empty, }; - _ = _orderOperationRecordEsRepository.AddAsync(index); + _ = orderOperationRecordEsRepository.AddAsync(index); return new IdBaseDto { Id = order.Id }; } order = await BuiltOrder(input); - var orderId = await _orderRepository.CreateOrderAsync(order); + var orderId = await orderRepository.CreateOrderAsync(order); var indexForAdd = new OrderOperationRecordIndex { @@ -107,7 +107,7 @@ public partial class OrderService CreateUserName = CurrentUser.UserName ?? string.Empty, CreateTime = DateTime.Now }; - _ = _orderOperationRecordEsRepository.AddAsync(indexForAdd); + _ = orderOperationRecordEsRepository.AddAsync(indexForAdd); return new IdBaseDto { Id = orderId }; } @@ -119,7 +119,7 @@ public partial class OrderService [VerifySignature] public async Task UpsertMasterOrderAsync(UpsertMasterOrderInput input) { - var order = await _orderRepository.GetFirstAsync(x => + var order = await orderRepository.GetFirstAsync(x => x.AppKey == AppKey && x.OrderType == TrackOrderType.主单 && x.OrderNo == input.MasterNo); if (order != null) { @@ -127,7 +127,7 @@ public partial class OrderService order = await BuiltOrder(input); ApplyUpsertOntoExisting(order, existing, resetTrackInfoWhenTrackNoChanged: false); - await _orderRepository.UpdateOrderAsync(order); + await orderRepository.UpdateOrderAsync(order); var index = new OrderOperationRecordIndex { @@ -139,13 +139,13 @@ public partial class OrderService CreateUserName = CurrentUser.UserName ?? string.Empty, }; - _ = _orderOperationRecordEsRepository.AddAsync(index); + _ = orderOperationRecordEsRepository.AddAsync(index); return new IdBaseDto { Id = order.Id }; } order = await BuiltOrder(input); - var orderId = await _orderRepository.CreateOrderAsync(order); + var orderId = await orderRepository.CreateOrderAsync(order); var indexForAdd = new OrderOperationRecordIndex { @@ -157,7 +157,7 @@ public partial class OrderService CreateUserName = CurrentUser.UserName ?? string.Empty, CreateTime = DateTime.Now }; - _ = _orderOperationRecordEsRepository.AddAsync(indexForAdd); + _ = orderOperationRecordEsRepository.AddAsync(indexForAdd); return new IdBaseDto { Id = orderId }; } @@ -183,7 +183,7 @@ public partial class OrderService ArrivalEmail = input.Consignee.Email, }; - var config = await _trackPullConfigRepository + var config = await trackPullConfigRepository .FirstOrDefaultAsync(x => x.AppKey == AppKey && x.ServiceProviderCode == input.ApiCode && x.OrderType == TrackOrderType.小包); @@ -220,7 +220,7 @@ public partial class OrderService return order; } - var config = await _trackPullConfigRepository + var config = await trackPullConfigRepository .FirstOrDefaultAsync(x => x.AppKey == AppKey && x.ServiceProviderCode == input.ApiCode && x.OrderType == TrackOrderType.大包); @@ -250,7 +250,7 @@ public partial class OrderService order.OrderFlights = new List(); - var config = await _trackPullConfigRepository + var config = await trackPullConfigRepository .FirstOrDefaultAsync(x => x.AppKey == AppKey && x.ServiceProviderCode == input.ApiCode && x.OrderType == TrackOrderType.小包); diff --git a/src/TrackCenter.Application/Services/ProvideServices/OrderService.cs b/src/TrackCenter.Application/Services/ProvideServices/OrderService.cs index 4c733266..9211d0e2 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/OrderService.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/OrderService.cs @@ -1,4 +1,4 @@ -using DotNetCore.CAP; +using Fake.EventBus.Distributed; using TrackCenter.Application.Dtos.ProvideServices; using TrackCenter.Domain.Aggregates.OrderAggregate; using TrackCenter.Domain.Aggregates.TrackDetailsAggregate; @@ -13,30 +13,15 @@ namespace TrackCenter.Application.Services.ProvideServices; /// [ApiExplorerSettings(GroupName = "OpenApi")] [Route("/ProviderService")] -public partial class OrderService : ApplicationServiceBase +public partial class OrderService( + IOrderRepository orderRepository, + IOrderOperationRecordEsRepository orderOperationRecordEsRepository, + ITrackPullConfigRepository trackPullConfigRepository, + IDistributedEventBus eventBus, + ITrackDetailsEsRepository trackDetailsEsRepository, + IServiceProvider serviceProvider) + : ApplicationServiceBase { - private readonly IOrderRepository _orderRepository; - private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository; - private readonly ITrackPullConfigRepository _trackPullConfigRepository; - private readonly IServiceProvider _serviceProvider; - - public OrderService( - IOrderRepository orderRepository, - IOrderOperationRecordEsRepository orderOperationRecordEsRepository, - ITrackPullConfigRepository trackPullConfigRepository, - ICapPublisher capPublisher, - ITrackDetailsEsRepository trackDetailsEsRepository, - IServiceProvider serviceProvider - ) - { - _orderRepository = orderRepository; - _orderOperationRecordEsRepository = orderOperationRecordEsRepository; - _trackPullConfigRepository = trackPullConfigRepository; - _serviceProvider = serviceProvider; - _trackDetailsEsRepository = trackDetailsEsRepository; - _capPublisher = capPublisher; - } - /// /// 删除订单 /// @@ -46,14 +31,14 @@ public partial class OrderService : ApplicationServiceBase [HttpPost("Order/Delete")] public async Task DeleteOrderAsync(DeleteOrderInput input) { - var order = await _orderRepository.GetFirstAsync(x => + var order = await orderRepository.GetFirstAsync(x => x.AppKey == input.AppKey && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo); if (order == null) { throw ProviderServiceActionResult.Exception("删除订单失败", $"订单:{input.OrderNo}不存在"); } - await _orderRepository.DeleteOrderAsync(order.Id); + await orderRepository.DeleteOrderAsync(order.Id); // 预警计算 WarningCalc_OrderDeletedOrCompleted(order); @@ -66,7 +51,7 @@ public partial class OrderService : ApplicationServiceBase order.IsDeleted = true; _ = Task.Run(async () => { - var scope = _serviceProvider.CreateAsyncScope(); + var scope = serviceProvider.CreateAsyncScope(); try { var handler = scope.ServiceProvider.GetRequiredService(); diff --git a/src/TrackCenter.Application/Services/ProvideServices/TrackPullService.cs b/src/TrackCenter.Application/Services/ProvideServices/TrackPullService.cs index a4248da4..031e0c06 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/TrackPullService.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/TrackPullService.cs @@ -15,21 +15,12 @@ namespace TrackCenter.Application.Services.ProvideServices; /// [ApiExplorerSettings(GroupName = "OpenApi")] [Route("/ProviderService")] -public class TrackPullService : ApplicationServiceBase +public class TrackPullService( + ProvideQueries provideQueries, + InterfaceForwardService interfaceForwardService, + IOptionsMonitor options) + : ApplicationServiceBase { - private readonly IOptionsMonitor _options; - private readonly ProvideQueries _provideQueries; - private readonly InterfaceForwardService _interfaceForwardService; - - public TrackPullService(ProvideQueries provideQueries, - InterfaceForwardService interfaceForwardService, - IOptionsMonitor options) - { - _provideQueries = provideQueries; - _interfaceForwardService = interfaceForwardService; - _options = options; - } - /// /// 手动刷新轨迹 /// @@ -46,7 +37,7 @@ public class TrackPullService : ApplicationServiceBase // tips:这里没有区分订单类型,就算的不同类型的单一起刷新了也无所谓 var (orders, skipReasons) = - await _provideQueries.DiagnoseManualRefreshAsync(input.AppKey, input.OrderNos); + await provideQueries.DiagnoseManualRefreshAsync(input.AppKey, input.OrderNos); if (orders.Count == 0) { @@ -79,8 +70,8 @@ public class TrackPullService : ApplicationServiceBase using (Track2InterfaceRelayAppContext.Use( new Track2InterfaceRelayAppContext(group.Key.AppKey))) { - var res = await _interfaceForwardService.BatchForwardThenPushToQueueAsync( - _options.CurrentValue.GetTrackInterfaceCode, serviceProviderCode, data, + var res = await interfaceForwardService.BatchForwardThenPushToQueueAsync( + options.CurrentValue.GetTrackInterfaceCode, serviceProviderCode, data, GlobalConst.TrackRefreshSubscribe, attach); diff --git a/src/TrackCenter.Application/Services/ProvideServices/TrackPushService.cs b/src/TrackCenter.Application/Services/ProvideServices/TrackPushService.cs index 4afc5335..f371e4ba 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/TrackPushService.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/TrackPushService.cs @@ -1,4 +1,6 @@ -using DotNetCore.CAP; +using System.Data; +using Fake.EventBus.Distributed; +using Fake.UnitOfWork; using TrackCenter.Application.Dtos.ProvideServices; using TrackCenter.Application.Dtos.TrackOrder; using TrackCenter.Application.Dtos.TrackPush; @@ -18,20 +20,20 @@ namespace TrackCenter.Application.Services.ProvideServices; [Route("/ProviderService")] public class TrackPushService : ApplicationServiceBase { - private readonly ICapPublisher _capPublisher; + private readonly IDistributedEventBus _eventBus; private readonly IOrderRepository _orderRepository; private readonly ITrackPushConfigRepository _trackPushConfigRepository; private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository; private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; public TrackPushService(IOrderRepository orderRepository - , ICapPublisher capPublisher + , IDistributedEventBus eventBus , ITrackPushRecordEsRepository trackPushRecordEsRepository , ITrackPushConfigRepository trackPushConfigRepository, ITrackDetailsEsRepository trackDetailsEsRepository) { _orderRepository = orderRepository; - _capPublisher = capPublisher; + _eventBus = eventBus; _trackPushRecordEsRepository = trackPushRecordEsRepository; _trackPushConfigRepository = trackPushConfigRepository; _trackDetailsEsRepository = trackDetailsEsRepository; @@ -43,7 +45,8 @@ public class TrackPushService : ApplicationServiceBase /// /// [HttpPost("Track/Push")] - public async Task PushTrackAsync(PushTrackInput input) + [UnitOfWork(IsTransactional = true, IsolationLevel = IsolationLevel.ReadCommitted)] + public virtual async Task PushTrackAsync(PushTrackInput input) { input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); if (input.OrderNos.Count == 0) @@ -152,7 +155,7 @@ public class TrackPushService : ApplicationServiceBase } }; - await _capPublisher.PublishAsync(GlobalConst.TrackManualPushSubscribe, trackPushEvent); + await _eventBus.PublishAsync(trackPushEvent); pushedOrderNos.Add(order.OrderNo); } diff --git a/src/TrackCenter.Application/Services/ProvideServices/TrackService.Query.cs b/src/TrackCenter.Application/Services/ProvideServices/TrackService.Query.cs index 44f58896..26b44fca 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/TrackService.Query.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/TrackService.Query.cs @@ -13,7 +13,7 @@ namespace TrackCenter.Application.Services.ProvideServices; /// public partial class TrackService { - private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository = trackDetailsEsRepository; private readonly IHttpContextAccessor _contextAccessor; private IObjectStorage ObjectStorage => LazyServiceProvider.GetRequiredService(); diff --git a/src/TrackCenter.Application/Services/ProvideServices/TrackService.cs b/src/TrackCenter.Application/Services/ProvideServices/TrackService.cs index 70189343..0a4d22e0 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/TrackService.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/TrackService.cs @@ -1,4 +1,6 @@ -using DotNetCore.CAP; +using System.Data; +using Fake.EventBus.Distributed; +using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; using TrackCenter.Application.Dtos.ProvideServices; using TrackCenter.Application.Events; @@ -15,34 +17,23 @@ namespace TrackCenter.Application.Services.ProvideServices; /// [ApiExplorerSettings(GroupName = "OpenApi")] [Route("/ProviderService")] -public partial class TrackService : ApplicationServiceBase +public partial class TrackService( + IOrderRepository orderRepository, + IDistributedEventBus eventBus, + ITrackDetailsEsRepository trackDetailsEsRepository, + ITrackContentRepository trackContentRepository) + : ApplicationServiceBase { - private readonly ICapPublisher _capPublisher; - private readonly IOrderRepository _orderRepository; - private readonly ITrackContentRepository _trackContentRepository; - - public TrackService( - IOrderRepository orderRepository, - ICapPublisher capPublisher, - ITrackDetailsEsRepository trackDetailsEsRepository, - ITrackContentRepository trackContentRepository - ) - { - _orderRepository = orderRepository; - _capPublisher = capPublisher; - _trackContentRepository = trackContentRepository; - _trackDetailsEsRepository = trackDetailsEsRepository; - } - /// /// 删除轨迹 /// /// /// [HttpPost("Track/Delete")] - public async Task DeleteTrackAsync(DeleteTrackInput input) + [UnitOfWork(IsTransactional = true, IsolationLevel = IsolationLevel.ReadCommitted)] + public virtual async Task DeleteTrackAsync(DeleteTrackInput input) { - var orderId = await _orderRepository.GetFirstAsync(x => + var orderId = await orderRepository.GetFirstAsync(x => x.AppKey == input.AppKey && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, @@ -99,7 +90,7 @@ public partial class TrackService : ApplicationServiceBase } // 删除轨迹(异步) - await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, new TrackDeleteEvent + await eventBus.PublishAsync(new TrackDeleteEvent { EsIds = esIds, OrderIds = new[] { orderId }, @@ -118,10 +109,11 @@ public partial class TrackService : ApplicationServiceBase /// /// [HttpPost("Track/BatchDelete")] - public async Task BatchDeleteTrackAsync(BatchDeleteTrackInput input) + [UnitOfWork(IsTransactional = true, IsolationLevel = IsolationLevel.ReadCommitted)] + public virtual async Task BatchDeleteTrackAsync(BatchDeleteTrackInput input) { input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 - var orders = await _orderRepository.GetListAsync(x => + var orders = await orderRepository.GetListAsync(x => x.AppKey == input.AppKey && x.OrderType == input.OrderType && input.OrderNos.Contains(x.OrderNo), @@ -173,7 +165,7 @@ public partial class TrackService : ApplicationServiceBase AppKey = input.AppKey, OperationMan = CurrentUser.UserName }; - await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event); + await eventBus.PublishAsync(@event); } /// @@ -182,11 +174,12 @@ public partial class TrackService : ApplicationServiceBase /// /// [HttpPost("Track/Upsert")] - public async Task UpsertTrackAsync(UpsertTrackInput input) + [UnitOfWork(IsTransactional = true, IsolationLevel = IsolationLevel.ReadCommitted)] + public virtual async Task UpsertTrackAsync(UpsertTrackInput input) { using var activity = ActivityHelper.CreateSpanActivity("UpsertTrack"); activity.SetTag("UpsertTrackInput", input.ToJson()); - var order = await _orderRepository.GetFirstAsync(x => + var order = await orderRepository.GetFirstAsync(x => x.AppKey == input.AppKey && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, @@ -226,7 +219,7 @@ public partial class TrackService : ApplicationServiceBase } }; @event.OperationMan = CurrentUser.UserName; - await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event); + await eventBus.PublishAsync(@event); } /// @@ -235,12 +228,13 @@ public partial class TrackService : ApplicationServiceBase /// /// [HttpPost("Track/BatchUpsert")] - public async Task BatchUpsertTrackAsync(BatchUpsertTrackInput input) + [UnitOfWork(IsTransactional = true, IsolationLevel = IsolationLevel.ReadCommitted)] + public virtual async Task BatchUpsertTrackAsync(BatchUpsertTrackInput input) { using var activity = ActivityHelper.CreateSpanActivity("BatchUpsert"); activity.SetTag("BatchUpsertTrackInput", input.ToJson()); input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); - var orders = await _orderRepository.GetListAsync(x => + var orders = await orderRepository.GetListAsync(x => x.AppKey == input.AppKey && x.OrderType == input.OrderType && input.OrderNos.Contains(x.OrderNo), @@ -298,7 +292,7 @@ public partial class TrackService : ApplicationServiceBase ForcedPush = input.ForcedPush, IsToMq = input.IsToMq, }; - await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event); + await eventBus.PublishAsync(@event); } } @@ -339,7 +333,7 @@ public partial class TrackService : ApplicationServiceBase #region 轨迹内容中的配置规则检查 - var trackContent = await _trackContentRepository.GetByCodeAsync(appKey, trackCode); + var trackContent = await trackContentRepository.GetByCodeAsync(appKey, trackCode); if (trackContent == null) { throw ProviderServiceActionResult.Exception("校验失败", $"轨迹代码:{trackCode}轨迹内容不存在"); diff --git a/src/TrackCenter.Application/Services/TimerTaskss/TrackPullTask.cs b/src/TrackCenter.Application/Services/TimerTaskss/TrackPullTask.cs index e8c7818b..8aeb3006 100644 --- a/src/TrackCenter.Application/Services/TimerTaskss/TrackPullTask.cs +++ b/src/TrackCenter.Application/Services/TimerTaskss/TrackPullTask.cs @@ -28,14 +28,14 @@ public class TrackPullTask( ProvideQueries provideQueries, InterfaceForwardService interfaceForwardService, IOptions interfaceOptions) - : ApplicationServiceBase, ITransientDependency + : ApplicationServiceBase { /// /// 定时任务刷新轨迹 /// /// [DisableConcurrentExecution(timeoutInSeconds: 1800)] - [UnitOfWork] + [UnitOfWork(IsTransactional = true)] [HttpPost("/TimerTask/Refresh")] public virtual async Task RefreshForTaskAsync() { @@ -66,7 +66,7 @@ public class TrackPullTask( return true; } - [UnitOfWork] + [UnitOfWork(IsTransactional = true)] public virtual async Task RefreshForConfigAsync(TrackPullConfigVo config) { var redisKey = trackPullCacheService.TrackPullKey(config); @@ -89,7 +89,7 @@ public class TrackPullTask( } } - protected async Task DoRefreshAsync(TrackPullConfigVo config, ProvideQueries provideQueries, + protected async Task DoRefreshAsync(TrackPullConfigVo config, ProvideQueries queries, InterfaceForwardService interfaceForward, InterfaceRelayParamsConfigOptions interfaceOptionsValue) { @@ -97,7 +97,7 @@ public class TrackPullTask( { var page = 1; var orders = - await provideQueries.FindOrderWithServiceProviderAsync(config, page); + await queries.FindOrderWithServiceProviderAsync(config, page); while (orders.Any()) { var serviceProviderCode = orders.First().ServiceProviderCode; @@ -122,7 +122,7 @@ public class TrackPullTask( } } - orders = await provideQueries.FindOrderWithServiceProviderAsync(config, ++page); + orders = await queries.FindOrderWithServiceProviderAsync(config, ++page); } } } diff --git a/src/TrackCenter.Application/Services/TrackOrders/TrackOrderService.cs b/src/TrackCenter.Application/Services/TrackOrders/TrackOrderService.cs index f9c05bb0..9faaebcb 100644 --- a/src/TrackCenter.Application/Services/TrackOrders/TrackOrderService.cs +++ b/src/TrackCenter.Application/Services/TrackOrders/TrackOrderService.cs @@ -21,29 +21,16 @@ namespace TrackCenter.Application.Services.TrackOrders; /// [ApiExplorerSettings(GroupName = "轨迹订单")] [Route("/Track/Order")] -public class TrackOrderService : ApplicationServiceBase +public class TrackOrderService( + IOrderRepository orderRepository, + ITrackDetailsEsRepository trackDetailsEsRepository, + ITrackPushRecordEsRepository trackPushRecordEsRepository, + IOrderOperationRecordEsRepository orderOperationRecordEsRepository, + IServiceProvider serviceProvider) + : ApplicationServiceBase { - private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository; - private readonly IOrderRepository _orderRepository; - private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; - private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository; - private readonly IServiceProvider _serviceProvider; private IObjectStorage ObjectStorage => LazyServiceProvider.GetRequiredService(); - public TrackOrderService( - IOrderRepository orderRepository, - ITrackDetailsEsRepository trackDetailsEsRepository, - ITrackPushRecordEsRepository trackPushRecordEsRepository, - IOrderOperationRecordEsRepository orderOperationRecordEsRepository, - IServiceProvider serviceProvider) - { - _orderRepository = orderRepository; - _trackDetailsEsRepository = trackDetailsEsRepository; - _trackPushRecordEsRepository = trackPushRecordEsRepository; - _orderOperationRecordEsRepository = orderOperationRecordEsRepository; - _serviceProvider = serviceProvider; - } - #region 轨迹订单列表 /// @@ -55,7 +42,7 @@ public class TrackOrderService : ApplicationServiceBase public async Task> GetTrackOrderPagedList(GetPageTrackOrderInput input) { var vo = ObjectMapper.Map(input); - var pageList = await _orderRepository.GetTrackOrderPagedList(vo); + var pageList = await orderRepository.GetTrackOrderPagedList(vo); return pageList; } @@ -70,7 +57,7 @@ public class TrackOrderService : ApplicationServiceBase [HttpPost("UpdateOrderStatus")] public async Task UpdateOrderStatus(UpdateOrderStatusInput input) { - var order = await _orderRepository.GetFirstAsync(x => x.Id == input.OrderId); + var order = await orderRepository.GetFirstAsync(x => x.Id == input.OrderId); if (order == null) throw new BusinessException(message: "订单不存在"); @@ -81,7 +68,7 @@ public class TrackOrderService : ApplicationServiceBase } order.IsCompleted = input.IsCompleted; - var b = await _orderRepository.UpdateColumnAsync(order, x => new + var b = await orderRepository.UpdateColumnAsync(order, x => new { x.IsCompleted }); @@ -101,7 +88,7 @@ public class TrackOrderService : ApplicationServiceBase [HttpGet("GetTrackPushRecords")] public async Task> GetTrackPushRecordsAsync(int orderId) { - var records = await _trackPushRecordEsRepository.GetTrackPushRecordsAsync(orderId); + var records = await trackPushRecordEsRepository.GetTrackPushRecordsAsync(orderId); var res = ObjectMapper.Map, List>(records); @@ -139,13 +126,13 @@ public class TrackOrderService : ApplicationServiceBase if (whereExpression == default) throw new BusinessException(message: "请求参数异常"); - var order = await _orderRepository.GetFirstAsync(whereExpression); + var order = await orderRepository.GetFirstAsync(whereExpression); if (order == default) { throw new BusinessException(message: "订单不存在"); } - var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id); + var trackDetails = await trackDetailsEsRepository.GetListAsync(order.Id); if (trackDetails.IsNullOrEmpty()) { return new List(); @@ -209,11 +196,11 @@ public class TrackOrderService : ApplicationServiceBase { var res = new List(); - var order = await _orderRepository.GetFirstAsync(m => m.OrderNo == input.OrderNumber); + var order = await orderRepository.GetFirstAsync(m => m.OrderNo == input.OrderNumber); if (order == null) throw new BusinessException("订单不存在"); - var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id); + var trackDetails = await trackDetailsEsRepository.GetListAsync(order.Id); //时间轴不显示轨迹内容为空的轨迹,进行过滤 trackDetails = trackDetails.Where(x => !x.TrackContent.IsNullOrWhiteSpace() && x.TrackContent != GlobalConst.EmptyString).ToList(); @@ -278,7 +265,7 @@ public class TrackOrderService : ApplicationServiceBase [HttpPost("DeleteTrackById")] public async Task DeleteTrackByIdAsync(string trackId) { - var track = await _trackDetailsEsRepository.GetByIdAsync(trackId); + var track = await trackDetailsEsRepository.GetByIdAsync(trackId); // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract if (track == null) @@ -286,7 +273,7 @@ public class TrackOrderService : ApplicationServiceBase throw new BusinessException(message: "轨迹不存在!"); } - await _trackDetailsEsRepository.DeleteTrackByIdAsync(trackId, track.IndexName); + await trackDetailsEsRepository.DeleteTrackByIdAsync(trackId, track.IndexName); return true; } @@ -298,14 +285,14 @@ public class TrackOrderService : ApplicationServiceBase [HttpGet("GetOrderOperationsById")] public async Task> GetOrderOperationsByIdAsync(int orderId) { - return await _orderOperationRecordEsRepository.GetOrderOperationsByIdAsync(orderId); + return await orderOperationRecordEsRepository.GetOrderOperationsByIdAsync(orderId); } private void WarningCalc_OrderDeletedOrCompleted(OrderEntity order) { _ = Task.Run(async () => { - var scope = _serviceProvider.CreateAsyncScope(); + var scope = serviceProvider.CreateAsyncScope(); try { var handler = scope.ServiceProvider.GetRequiredService(); diff --git a/src/TrackCenter.Application/Services/Warning/ReturnWarningService.cs b/src/TrackCenter.Application/Services/Warning/ReturnWarningService.cs index c144a493..368d0c6d 100644 --- a/src/TrackCenter.Application/Services/Warning/ReturnWarningService.cs +++ b/src/TrackCenter.Application/Services/Warning/ReturnWarningService.cs @@ -1,5 +1,7 @@ -using DotNetCore.CAP; +using System.Data; +using Fake.EventBus.Distributed; using Fake.Domain.Dtos; +using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; using TrackCenter.Application.Dtos.Warning; using TrackCenter.Application.Dtos.Warning.Return; @@ -25,7 +27,7 @@ public class ReturnWarningService : ApplicationServiceBase private readonly IReturnWarningHandler _returnWarningHandler; private readonly IWarningRuleRepository _warningRuleRepository; private readonly IWarningDetailsEsRepository _warningDetailsEsRepository; - private readonly ICapPublisher _capPublisher; + private readonly IDistributedEventBus _eventBus; private readonly TrackStatusNameDictCache _trackStatusNameDictCache; private readonly AppNameDictCache _appNameDictCache; @@ -34,7 +36,7 @@ public class ReturnWarningService : ApplicationServiceBase IReturnWarningHandler returnWarningHandler, IWarningRuleRepository warningRuleRepository, IWarningDetailsEsRepository warningDetailsEsRepository, - ICapPublisher capPublisher, + IDistributedEventBus eventBus, TrackStatusNameDictCache trackStatusNameDictCache, AppNameDictCache appNameDictCache ) @@ -43,7 +45,7 @@ public class ReturnWarningService : ApplicationServiceBase _returnWarningHandler = returnWarningHandler; _warningRuleRepository = warningRuleRepository; _warningDetailsEsRepository = warningDetailsEsRepository; - _capPublisher = capPublisher; + _eventBus = eventBus; _trackStatusNameDictCache = trackStatusNameDictCache; _appNameDictCache = appNameDictCache; } @@ -220,7 +222,8 @@ public class ReturnWarningService : ApplicationServiceBase /// /// [HttpPost("ReturnPush")] - public async Task ReturnPush(ReturnPushInput input) + [UnitOfWork(IsTransactional = true, IsolationLevel = IsolationLevel.ReadCommitted)] + public virtual async Task ReturnPush(ReturnPushInput input) { if (input.WarningDetailIds.Count == 0) { @@ -276,7 +279,7 @@ public class ReturnWarningService : ApplicationServiceBase } }; - await _capPublisher.PublishAsync(GlobalConst.TrackManualPushSubscribe, trackPushEvent); + await _eventBus.PublishAsync(trackPushEvent); } return $"即将进行{filtered.Count}个回传推送!"; diff --git a/src/TrackCenter.Application/TrackCenter.Application.csproj b/src/TrackCenter.Application/TrackCenter.Application.csproj index d1d3f4ba..ccab7abc 100644 --- a/src/TrackCenter.Application/TrackCenter.Application.csproj +++ b/src/TrackCenter.Application/TrackCenter.Application.csproj @@ -1,4 +1,4 @@ - + @@ -10,6 +10,7 @@ + @@ -19,12 +20,6 @@ - - - - - - diff --git a/src/TrackCenter.Application/TrackCenterApplicationModule.cs b/src/TrackCenter.Application/TrackCenterApplicationModule.cs index 0137323b..4c0de9ef 100644 --- a/src/TrackCenter.Application/TrackCenterApplicationModule.cs +++ b/src/TrackCenter.Application/TrackCenterApplicationModule.cs @@ -1,8 +1,5 @@ using System.Diagnostics; using System.Net; -using DotNetCore.CAP; -using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Messages; using Fake; using Fake.EventBus.RabbitMQ; using Fake.Modularity; @@ -16,9 +13,7 @@ using InterfaceForward.Domain.Shared.Helpers; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using RabbitMQ.Client; -using Savorboard.CAP.InMemoryMessageQueue; using TrackCenter.Application.Kafka; -using TrackCenter.Application.CAP; using TrackCenter.Application.HostServices; using TrackCenter.Application.Options; using TrackCenter.Application.Rabbit; @@ -41,62 +36,6 @@ public class TrackCenterApplicationModule : FakeModule options.ScanProfiles(); }); - var rabbitOptions = configuration.GetSection("RabbitMQ").Get()!.Default; - - #region CAP - - context.Services.AddSingleton(); - if (!Debugger.IsAttached) - { - context.Services.AddCap(options => - { - options.UseMySql(configuration["ConnectionStrings:Default"]!); - options.UseRabbitMQ(configure => - { - configure.HostName = rabbitOptions.HostName; - configure.UserName = rabbitOptions.UserName; - configure.Password = rabbitOptions.Password; - configure.Port = rabbitOptions.Port; - configure.BasicQosOptions = - new RabbitMQOptions.BasicQos(configuration.GetValue("CAP:PrefetchCount")); - }); - options.FailedRetryInterval = configuration.GetValue("CAP:FailedRetryInterval"); - options.FailedRetryCount = configuration.GetValue("CAP:FailedRetryCount"); - options.SucceedMessageExpiredAfter = configuration.GetValue("CAP:SucceedMessageExpiredAfter"); - options.FallbackWindowLookbackSeconds = - configuration.GetValue("CAP:FallbackWindowLookbackSeconds"); - - options.UseDashboard(dashboardOptions => { dashboardOptions.PathBase = configuration["ASPNETCORE_PATHBASE"]; }); - options.FailedThresholdCallback = faileCalback => - { - try - { - Log.Error($@" - |-CAP失败回调事件: - |-处理类型:{(faileCalback.MessageType == MessageType.Subscribe ? "消费消息达到最大重试次数,需要开发人员介入" : "生产消息推送失败")} - |-头部信息:{faileCalback.Message.Headers.ToJson()}"); - } - catch (Exception ex) - { - Log.Error("【严重】CAP失败回调事件发生未处理异常" + ex); - } - }; - }).AddSubscribeFilter(); - } - else - { - //是本地调试环境,用内存存储和内存队列 - context.Services.AddCap(capOptions => - { - capOptions.UseInMemoryStorage(); - capOptions.UseInMemoryMessageQueue(); - capOptions.UseDashboard(); - }).AddSubscribeFilter(); - context.Services.GetInitLogger().LogInformation("-- 当前为本地环境,用内存存储和内存队列"); - } - - #endregion - var redisOptions = configuration.GetSection("Redis").Get(); if (redisOptions == null) throw new FakeException("未找到Redis相关配置,请检查配置文件中是否包含名为Redis的节点"); -- 2.45.2 From 5c7829bdbd6cb12bfcd9074b0ef9fd34251f438f Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Tue, 27 Oct 2026 16:32:14 +0800 Subject: [PATCH 3/3] feat: fake up --- Directory.Build.props | 2 +- src/TrackCenter.Api/TrackCenter.Api.csproj | 3 +- src/TrackCenter.Api/TrackCenterApiModule.cs | 25 ++- .../InterfaceRelayForwardReplayEvent.cs | 10 +- .../Events/OrderPodPullEvent.cs | 5 +- .../TrackChangeAfterUpdateOrderEvent.cs | 5 +- .../Events/TrackDeleteEvent.cs | 5 +- .../Events/TrackPushEvent.cs | 5 +- .../Events/TrackUpsertEvent.cs | 5 +- .../Events/TrackUpsertForRefreshEvent.cs | 2 + ...TrackChangeAfterUpdateOrderEventHandler.cs | 6 +- .../Messaging/TrackDeleteEventHandler.cs | 17 +- .../TrackPushCompletedEventHandler.cs | 71 +++----- .../Messaging/TrackPushEventHandler.cs | 5 +- .../TrackRefreshEventHandler.cs | 54 ++---- .../Messaging/TrackUpsertEventHandler.cs | 33 ++-- .../Rabbit/IRabbitHandler.cs | 10 -- .../Rabbit/RabbitClient.cs | 166 ------------------ .../Rabbit/RabbitInstrumentation.cs | 21 --- .../Rabbit/RabbitOptions.cs | 84 --------- .../Broadcasting/BroadcastingService.cs | 76 +++++--- .../ProvideServices/OrderService.Link.cs | 6 +- .../Services/ProvideServices/OrderService.cs | 4 +- .../ProvideServices/TrackPushService.cs | 10 +- .../Services/ProvideServices/TrackService.cs | 12 +- .../Services/Warning/ReturnWarningService.cs | 10 +- .../TrackCenter.Application.csproj | 3 +- .../TrackCenterApplicationModule.cs | 67 +++---- 28 files changed, 204 insertions(+), 518 deletions(-) rename src/TrackCenter.Application/{Rabbit => Events}/InterfaceRelayForwardReplayEvent.cs (70%) rename src/TrackCenter.Application/{Rabbit => Messaging}/TrackPushCompletedEventHandler.cs (65%) rename src/TrackCenter.Application/{Rabbit => Messaging}/TrackRefreshEventHandler.cs (91%) delete mode 100644 src/TrackCenter.Application/Rabbit/IRabbitHandler.cs delete mode 100644 src/TrackCenter.Application/Rabbit/RabbitClient.cs delete mode 100644 src/TrackCenter.Application/Rabbit/RabbitInstrumentation.cs delete mode 100644 src/TrackCenter.Application/Rabbit/RabbitOptions.cs diff --git a/Directory.Build.props b/Directory.Build.props index 1f5eaf03..a4b16976 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,6 +4,6 @@ - 8.0.6 + 8.0.6.2 diff --git a/src/TrackCenter.Api/TrackCenter.Api.csproj b/src/TrackCenter.Api/TrackCenter.Api.csproj index 48e85830..9dff28a6 100644 --- a/src/TrackCenter.Api/TrackCenter.Api.csproj +++ b/src/TrackCenter.Api/TrackCenter.Api.csproj @@ -20,8 +20,7 @@ - - + diff --git a/src/TrackCenter.Api/TrackCenterApiModule.cs b/src/TrackCenter.Api/TrackCenterApiModule.cs index 7af17e9d..6fbba35d 100644 --- a/src/TrackCenter.Api/TrackCenterApiModule.cs +++ b/src/TrackCenter.Api/TrackCenterApiModule.cs @@ -5,8 +5,8 @@ using Fake.AspNetCore.ExceptionHandling; using Fake.AspNetCore.Newtonsoft; using Fake.AspNetCore.Swagger; using Fake.Autofac; -using Fake.EventBus.Dashboard; -using Fake.EventBus.IntegrationEventLog; +using Fake.Messaging.Dashboard; +using Fake.Messaging.EntityFrameworkCore; using Fake.FeiShu; using Fake.Json; using Fake.Modularity; @@ -33,9 +33,8 @@ namespace TrackCenter.Api; [DependsOn(typeof(FakeAspNetCoreModule))] [DependsOn(typeof(TrackCenterApplicationModule))] [DependsOn(typeof(TrackCenterRepositoryModule))] -// RabbitMQ 物理总线之后 Replace IDistributedEventBus → Outbox(与 admin 一致) -[DependsOn(typeof(FakeEventBusIntegrationEventLogModule))] -[DependsOn(typeof(FakeEventBusDashboardModule))] +// Messaging 独立队列(Outbox/Inbox + Dashboard);物理传输由 FakeMessagingRabbitMqModule 提供 +[DependsOn(typeof(FakeMessagingDashboardModule))] [DependsOn(typeof(FakeSerilogModule))] public class TrackCenterApiModule : FakeModule { @@ -59,10 +58,11 @@ public class TrackCenterApiModule : FakeModule // 配置签名验证选项 services.Configure(configuration.GetSection("SignatureValidation")); - // Outbox / Inbox 与业务同库(EF),通过 DbTransaction 征用 SqlSugar 事务 - services.AddDbContext(options => + // Outbox / Inbox(fk_msg_*)与业务同库(EF),通过 DbTransaction 征用 SqlSugar 事务 + services.AddDbContext(options => { - var connectionString = configuration.GetConnectionString("IntegrationEventLog") + var connectionString = configuration.GetConnectionString("Messaging") + ?? configuration.GetConnectionString("IntegrationEventLog") ?? configuration.GetConnectionString("Default") ?? configuration["ConnectionStrings:Default"] ?? string.Empty; @@ -73,6 +73,13 @@ public class TrackCenterApiModule : FakeModule #endif }); + // Dashboard 路径保持 /eventbus,兼容旧书签与网关 + services.Configure(o => + { + if (string.IsNullOrWhiteSpace(o.PathMatch) || o.PathMatch == "/messaging") + o.PathMatch = "/eventbus"; + }); + // 全局授权配置:所有接口默认需要授权 services.AddMvc(options => { @@ -207,7 +214,7 @@ public class TrackCenterApiModule : FakeModule }); // 必须在 UsePathBase 之后:完整对外路径为 {PathBase}/eventbus - app.UseFakeEventBusDashboard(); + app.UseFakeMessagingDashboard(); app.Services.GetRequiredService().Send("Application started"); } diff --git a/src/TrackCenter.Application/Rabbit/InterfaceRelayForwardReplayEvent.cs b/src/TrackCenter.Application/Events/InterfaceRelayForwardReplayEvent.cs similarity index 70% rename from src/TrackCenter.Application/Rabbit/InterfaceRelayForwardReplayEvent.cs rename to src/TrackCenter.Application/Events/InterfaceRelayForwardReplayEvent.cs index 0f9144ba..c3b171ef 100644 --- a/src/TrackCenter.Application/Rabbit/InterfaceRelayForwardReplayEvent.cs +++ b/src/TrackCenter.Application/Events/InterfaceRelayForwardReplayEvent.cs @@ -1,6 +1,12 @@ -namespace TrackCenter.Application.Rabbit; +using Fake.Messaging; -public class InterfaceRelayForwardReplayEvent +namespace TrackCenter.Application.Events; + +/// +/// 接口通回调报文(外部生产,无 Fake MessageId / DLX)。 +/// +[MessageRoute(Topic = GlobalConst.InterfaceRelayExchange, TopicType = "direct")] +public class InterfaceRelayForwardReplayEvent : Message { /// /// 请求Id diff --git a/src/TrackCenter.Application/Events/OrderPodPullEvent.cs b/src/TrackCenter.Application/Events/OrderPodPullEvent.cs index 3d09e256..e30746b0 100644 --- a/src/TrackCenter.Application/Events/OrderPodPullEvent.cs +++ b/src/TrackCenter.Application/Events/OrderPodPullEvent.cs @@ -1,4 +1,4 @@ -using Fake.EventBus.Distributed; +using Fake.Messaging; namespace TrackCenter.Application.Events; @@ -6,7 +6,8 @@ namespace TrackCenter.Application.Events; /// 订单 POD 拉取(当前仓库无订阅方,仍走 Outbox 投递以兼容后续消费者)。 /// [Serializable] -public class OrderPodPullEvent : IntegrationEvent +[MessageRoute(nameof(OrderPodPullEvent))] +public class OrderPodPullEvent : Message { // 确定应用 public string AppKey { get; set; } diff --git a/src/TrackCenter.Application/Events/TrackChangeAfterUpdateOrderEvent.cs b/src/TrackCenter.Application/Events/TrackChangeAfterUpdateOrderEvent.cs index e438598a..2f2acd1b 100644 --- a/src/TrackCenter.Application/Events/TrackChangeAfterUpdateOrderEvent.cs +++ b/src/TrackCenter.Application/Events/TrackChangeAfterUpdateOrderEvent.cs @@ -1,9 +1,10 @@ -using Fake.EventBus.Distributed; +using Fake.Messaging; namespace TrackCenter.Application.Events; [Serializable] -public class TrackChangeAfterUpdateOrderEvent : IntegrationEvent +[MessageRoute(nameof(TrackChangeAfterUpdateOrderEvent))] +public class TrackChangeAfterUpdateOrderEvent : Message { /// /// 订单Id diff --git a/src/TrackCenter.Application/Events/TrackDeleteEvent.cs b/src/TrackCenter.Application/Events/TrackDeleteEvent.cs index 8cac8130..46342712 100644 --- a/src/TrackCenter.Application/Events/TrackDeleteEvent.cs +++ b/src/TrackCenter.Application/Events/TrackDeleteEvent.cs @@ -1,10 +1,11 @@ -using Fake.EventBus.Distributed; +using Fake.Messaging; using TrackCenter.Application.Dtos.ProvideServices; namespace TrackCenter.Application.Events; [Serializable] -public class TrackDeleteEvent : IntegrationEvent +[MessageRoute(nameof(TrackDeleteEvent))] +public class TrackDeleteEvent : Message { /// /// 根据esId定位轨迹,优先级最高 diff --git a/src/TrackCenter.Application/Events/TrackPushEvent.cs b/src/TrackCenter.Application/Events/TrackPushEvent.cs index 53a63a8e..bd481ed1 100644 --- a/src/TrackCenter.Application/Events/TrackPushEvent.cs +++ b/src/TrackCenter.Application/Events/TrackPushEvent.cs @@ -1,4 +1,4 @@ -using Fake.EventBus.Distributed; +using Fake.Messaging; namespace TrackCenter.Application.Events; @@ -7,7 +7,8 @@ namespace TrackCenter.Application.Events; /// 每次可传递多个订单,但仅能传递同一个轨迹内容 /// [Serializable] -public class TrackPushEvent : IntegrationEvent +[MessageRoute(nameof(TrackPushEvent))] +public class TrackPushEvent : Message { /// /// 操作类型 diff --git a/src/TrackCenter.Application/Events/TrackUpsertEvent.cs b/src/TrackCenter.Application/Events/TrackUpsertEvent.cs index ee4ac79f..1931d689 100644 --- a/src/TrackCenter.Application/Events/TrackUpsertEvent.cs +++ b/src/TrackCenter.Application/Events/TrackUpsertEvent.cs @@ -1,10 +1,11 @@ -using Fake.EventBus.Distributed; +using Fake.Messaging; using TrackCenter.Application.Dtos.ProvideServices; namespace TrackCenter.Application.Events; [Serializable] -public class TrackUpsertEvent : IntegrationEvent +[MessageRoute(nameof(TrackUpsertEvent))] +public class TrackUpsertEvent : Message { /// /// 应用 diff --git a/src/TrackCenter.Application/Events/TrackUpsertForRefreshEvent.cs b/src/TrackCenter.Application/Events/TrackUpsertForRefreshEvent.cs index ef946ab7..5aefc531 100644 --- a/src/TrackCenter.Application/Events/TrackUpsertForRefreshEvent.cs +++ b/src/TrackCenter.Application/Events/TrackUpsertForRefreshEvent.cs @@ -1,9 +1,11 @@ +using Fake.Messaging; namespace TrackCenter.Application.Events; /// /// 轨迹刷新引发的新增/更新(独立队列,与 隔离)。 /// [Serializable] +[MessageRoute(nameof(TrackUpsertForRefreshEvent))] public class TrackUpsertForRefreshEvent : TrackUpsertEvent { } diff --git a/src/TrackCenter.Application/Messaging/TrackChangeAfterUpdateOrderEventHandler.cs b/src/TrackCenter.Application/Messaging/TrackChangeAfterUpdateOrderEventHandler.cs index 0da20f58..545011fe 100644 --- a/src/TrackCenter.Application/Messaging/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/TrackCenter.Application/Messaging/TrackChangeAfterUpdateOrderEventHandler.cs @@ -1,6 +1,4 @@ -using Fake.EventBus; -using Fake.EventBus.Distributed; -using Fake.UnitOfWork; +using Fake.Messaging; using TrackCenter.Application.Events; using TrackCenter.Application.Services.Warning.Handlers; using TrackCenter.Domain.Aggregates.OrderAggregate; @@ -8,7 +6,7 @@ using TrackCenter.Domain.Aggregates.OrderAggregate; namespace TrackCenter.Application.Messaging; public class TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository, IServiceProvider serviceProvider) - : IEventHandler, ITransientDependency + : IMessageHandle, ITransientDependency { public virtual async Task HandleAsync( TrackChangeAfterUpdateOrderEvent @event, diff --git a/src/TrackCenter.Application/Messaging/TrackDeleteEventHandler.cs b/src/TrackCenter.Application/Messaging/TrackDeleteEventHandler.cs index 09105b19..da2e0850 100644 --- a/src/TrackCenter.Application/Messaging/TrackDeleteEventHandler.cs +++ b/src/TrackCenter.Application/Messaging/TrackDeleteEventHandler.cs @@ -1,5 +1,4 @@ -using Fake.EventBus; -using Fake.EventBus.Distributed; +using Fake.Messaging; using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; using TrackCenter.Application.Dtos.ProvideServices; @@ -17,23 +16,23 @@ namespace TrackCenter.Application.Messaging; public class TrackDeleteEventHandler( ProvideQueries provideQueries, IOrderRepository orderRepository, - IDistributedEventBus eventBus, + IMessagePublisher messagePublisher, ITrackDetailsEsRepository trackDetailsEsRepository, IOrderOperationRecordEsRepository orderOperationRecordEsRepository, BroadcastingService broadcastingService, WarningSignalPublisher warningSignalPublisher) - : IEventHandler, ITransientDependency + : IMessageHandle, ITransientDependency { [UnitOfWork(IsTransactional = true)] - public virtual async Task HandleAsync(TrackDeleteEvent @event, CancellationToken cancellationToken = default) + public virtual async Task HandleAsync(TrackDeleteEvent message, CancellationToken cancellationToken = default) { - if (!CanDelete(@event)) return; + if (!CanDelete(message)) return; // 处理删除轨迹 - await HandleDeleteTrackAsync(@event); + await HandleDeleteTrackAsync(message); // 根据订单关联关系异步向下刷(异步) - await DownByOrderLink(@event); + await DownByOrderLink(message); } private async Task DownByOrderLink(TrackDeleteEvent @event) @@ -77,7 +76,7 @@ public class TrackDeleteEventHandler( var subEvent = nextEvent.DeepCopy(); subEvent.OrderIds = subOrderIds; // 关联单继续走删除链路(原 CAP 误发到 Upsert topic,此处修正) - await eventBus.PublishAsync(subEvent); + await messagePublisher.PublishAsync(subEvent); } } } diff --git a/src/TrackCenter.Application/Rabbit/TrackPushCompletedEventHandler.cs b/src/TrackCenter.Application/Messaging/TrackPushCompletedEventHandler.cs similarity index 65% rename from src/TrackCenter.Application/Rabbit/TrackPushCompletedEventHandler.cs rename to src/TrackCenter.Application/Messaging/TrackPushCompletedEventHandler.cs index 5c1ed968..8567f549 100644 --- a/src/TrackCenter.Application/Rabbit/TrackPushCompletedEventHandler.cs +++ b/src/TrackCenter.Application/Messaging/TrackPushCompletedEventHandler.cs @@ -1,63 +1,44 @@ -using System.Text; +using Fake.Messaging; using Fake.UnitOfWork; +using InterfaceForward.Domain.Shared.Helpers; using Newtonsoft.Json; -using RabbitMQ.Client.Events; using TrackCenter.Application.Dtos.TrackPush; +using TrackCenter.Application.Events; using TrackCenter.Application.Helpers; using TrackCenter.Application.Services.Broadcasting; using TrackCenter.Application.Services.Warning.Handlers; using TrackCenter.Domain.Aggregates.OrderAggregate; using TrackCenter.Domain.Aggregates.TrackPushAggregate; -namespace TrackCenter.Application.Rabbit; +namespace TrackCenter.Application.Messaging; -[ExposeServices(typeof(IRabbitHandler))] -public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandler +/// +/// 接口通轨迹推送完成回调 → 独立队列 。 +/// +[MessageSubscribe(GlobalConst.TrackPushCompletedSubscribe, ExternalQueue = true)] +public class TrackPushCompletedEventHandler( + IOrderRepository orderRepository, + ITrackPushRecordEsRepository trackPushRecordEsRepository, + BroadcastingService broadcastingService, + IReturnWarningHandler returnWarningHandler) + : IMessageHandle, ITransientDependency { - private readonly IOrderRepository _orderRepository; - private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository; - private readonly BroadcastingService _broadcastingService; - private readonly IReturnWarningHandler _returnWarningHandler; - - public TrackPushCompletedEventHandler(IOrderRepository orderRepository, - ITrackPushRecordEsRepository trackPushRecordEsRepository, - BroadcastingService broadcastingService, IReturnWarningHandler returnWarningHandler) + public virtual async Task HandleAsync( + InterfaceRelayForwardReplayEvent message, + CancellationToken cancellationToken = default) { - _orderRepository = orderRepository; - _trackPushRecordEsRepository = trackPushRecordEsRepository; - _broadcastingService = broadcastingService; - _returnWarningHandler = returnWarningHandler; - } - - public bool Enable(ConsumeOptions options) - { - return options.Queue.StartsWith(GlobalConst.TrackPushCompletedSubscribe); - } - - [UnitOfWork(IsTransactional = true)] - public virtual async Task Handle(BasicDeliverEventArgs args) - { - var msg = string.Empty; try { - msg = Encoding.UTF8.GetString(args.Body.ToArray()); - var @event = System.Text.Json.JsonSerializer.Deserialize(msg); - if (@event == null) - { - Log.Warning( - $"rabbit on queue received msg can't convert to {nameof(InterfaceRelayForwardReplayEvent)}"); - return; - } - - await ConsumerAsync(@event); + await ConsumerAsync(message); } catch (Exception ex) { - Log.Error($"TrackPushCompletedEventHandler出错,错误信息:{ex}\r\n-----\r\n消息:{msg}"); + Log.Error($"TrackPushCompletedEventHandler出错,错误信息:{ex}\r\n-----\r\n消息:{message.ToJson()}"); + throw; } } - public async Task ConsumerAsync(InterfaceRelayForwardReplayEvent @event) + private async Task ConsumerAsync(InterfaceRelayForwardReplayEvent @event) { var optionType = Base64Helper.DeSerialize(@event.Attach); var pushInputs = new List(); @@ -91,16 +72,16 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl // 推送广播 if (logs.First().IsToMq) - _broadcastingService.TrackPushCompletedPublicTopic(logs.Select(log => BuildDto(log, @event.Data)).ToList()); + broadcastingService.TrackPushCompletedPublicTopic(logs.Select(log => BuildDto(log, @event.Data)).ToList()); // 写入推送日志 - await _trackPushRecordEsRepository.AddManyAsync(logs); + await trackPushRecordEsRepository.AddManyAsync(logs); // 同步更新订单主表 await TrackPushAfterUpdateOrderAsync(isAdd, @event.IsSuccess, logs); // 引发预警计算 - await _returnWarningHandler.ReceiveTrackPushRecordHandleAsync(@event.IsSuccess, @event.RequestParams, logs, pushInputs, updateInputs); + await returnWarningHandler.ReceiveTrackPushRecordHandleAsync(@event.IsSuccess, @event.RequestParams, logs, pushInputs, updateInputs); } private async Task TrackPushAfterUpdateOrderAsync(bool isAdd, bool isSuccess, List logs) @@ -118,7 +99,7 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl LatestPushError = x.Message }).ToList(); - await _orderRepository.UpdateRangeAsync(orders, x => new + await orderRepository.UpdateRangeAsync(orders, x => new { x.QuestionType, x.LatestPushError @@ -136,7 +117,7 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl LatestPushTime = x.CreateTime, }).ToList(); - await _orderRepository.UpdateRangeAsync(orders, x => new + await orderRepository.UpdateRangeAsync(orders, x => new { x.QuestionType, x.LatestPushError, diff --git a/src/TrackCenter.Application/Messaging/TrackPushEventHandler.cs b/src/TrackCenter.Application/Messaging/TrackPushEventHandler.cs index 206796f1..8f852117 100644 --- a/src/TrackCenter.Application/Messaging/TrackPushEventHandler.cs +++ b/src/TrackCenter.Application/Messaging/TrackPushEventHandler.cs @@ -1,7 +1,6 @@ using System.Collections.Immutable; using System.Text.Json; -using Fake.EventBus; -using Fake.EventBus.Distributed; +using Fake.Messaging; using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; using Microsoft.Extensions.Options; @@ -29,7 +28,7 @@ public class TrackPushEventHandler( BroadcastingService broadcastingService, ITrackDetailsEsRepository trackDetailsEsRepository, InterfaceForwardService interfaceForwardService) - : IEventHandler, ITransientDependency + : IMessageHandle, ITransientDependency { private List _orders = null!; private List _pushConfigs = null!; diff --git a/src/TrackCenter.Application/Rabbit/TrackRefreshEventHandler.cs b/src/TrackCenter.Application/Messaging/TrackRefreshEventHandler.cs similarity index 91% rename from src/TrackCenter.Application/Rabbit/TrackRefreshEventHandler.cs rename to src/TrackCenter.Application/Messaging/TrackRefreshEventHandler.cs index ade732fe..544e4251 100644 --- a/src/TrackCenter.Application/Rabbit/TrackRefreshEventHandler.cs +++ b/src/TrackCenter.Application/Messaging/TrackRefreshEventHandler.cs @@ -1,13 +1,11 @@ using System.Diagnostics; -using System.Text; -using Fake.EventBus.Distributed; +using Fake.Messaging; using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using RabbitMQ.Client.Events; using TrackCenter.Application.Dtos.TrackPull; using TrackCenter.Application.Events; using TrackCenter.Application.Helpers; @@ -16,47 +14,37 @@ using TrackCenter.Application.Services.TrackPull; using TrackCenter.Domain.Aggregates.OrderAggregate; using TrackCenter.Domain.Aggregates.TrackDetailsAggregate; -namespace TrackCenter.Application.Rabbit; +namespace TrackCenter.Application.Messaging; -[ExposeServices(typeof(IRabbitHandler))] +/// +/// 接口通轨迹刷新回调 → 独立队列 。 +/// +[MessageSubscribe(GlobalConst.TrackRefreshSubscribe, ExternalQueue = true)] public class TrackRefreshEventHandler( IOrderRepository orderRepository, - IDistributedEventBus eventBus, + IMessagePublisher messagePublisher, TrackPullCacheService trackPullCacheService, ITrackDetailsEsRepository trackDetailsEsRepository, ILogger logger, IOptionsMonitor options) - : ITransientDependency, IRabbitHandler + : IMessageHandle, ITransientDependency { - public bool Enable(ConsumeOptions coptions) + public virtual async Task HandleAsync( + InterfaceRelayForwardReplayEvent message, + CancellationToken cancellationToken = default) { - return coptions.Queue.StartsWith(GlobalConst.TrackRefreshSubscribe); - } - - [UnitOfWork(IsTransactional = true)] - public virtual async Task Handle(BasicDeliverEventArgs args) - { - var msg = string.Empty; try { - msg = Encoding.UTF8.GetString(args.Body.ToArray()); - var @event = System.Text.Json.JsonSerializer.Deserialize(msg); - if (@event == null) - { - logger.LogWarning( - $"rabbit on queue received msg can't convert to {nameof(InterfaceRelayForwardReplayEvent)}"); - return; - } - - await ConsumerAsync(@event); + await ConsumerAsync(message); } catch (Exception ex) { - Log.Error($"TrackRefreshEventHandler出错,错误信息:{ex}\r\n-----\r\n消息:{msg}"); + Log.Error($"TrackRefreshEventHandler出错,错误信息:{ex}\r\n-----\r\n消息:{message.ToJson()}"); + throw; } } - public async Task ConsumerAsync(InterfaceRelayForwardReplayEvent @event) + private async Task ConsumerAsync(InterfaceRelayForwardReplayEvent @event) { if (!@event.IsSuccess) { @@ -71,15 +59,6 @@ public class TrackRefreshEventHandler( return; } - // 最优先级,最匹配的 权重 sort - - // 客户、渠道、产品 - // */*/* 全部 - // 客户A/渠道A/产品A - // 客户A - - // 客户A 渠道B 产品A - var config = await trackPullCacheService.GetPullParamsWithContentAsync(attach.AppKey, attach.ServiceProviderCode, attach.OrderType); if (config is null) @@ -134,7 +113,6 @@ public class TrackRefreshEventHandler( ServiceProviderCode = attach.ServiceProviderCode }; - if (trackToken is JArray trackTokens) { foreach (var item in trackTokens) @@ -284,7 +262,7 @@ public class TrackRefreshEventHandler( Extra = trackExtra }; - await eventBus.PublishAsync(trackUpsertEvent); + await messagePublisher.PublishAsync(trackUpsertEvent); } private async Task InsertNotMappedTrackAsync(JToken trackToken, TrackRefreshContext context, string? trackPlace, diff --git a/src/TrackCenter.Application/Messaging/TrackUpsertEventHandler.cs b/src/TrackCenter.Application/Messaging/TrackUpsertEventHandler.cs index 461d37eb..c464502f 100644 --- a/src/TrackCenter.Application/Messaging/TrackUpsertEventHandler.cs +++ b/src/TrackCenter.Application/Messaging/TrackUpsertEventHandler.cs @@ -1,5 +1,4 @@ -using Fake.EventBus; -using Fake.EventBus.Distributed; +using Fake.Messaging; using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; using TrackCenter.Application.Events; @@ -18,30 +17,22 @@ namespace TrackCenter.Application.Messaging; public class TrackUpsertEventHandler( IOrderRepository orderRepository, - IDistributedEventBus eventBus, + IMessagePublisher messagePublisher, ProvideQueries provideQueries, ITrackDetailsEsRepository trackDetailsEsRepository, IOrderOperationRecordEsRepository orderOperationRecordEsRepository, BroadcastingService broadcastingService, WarningSignalPublisher warningSignalPublisher) : - IEventHandler, - IEventHandler, + IMessageHandle, + IMessageHandle, ITransientDependency { - Task IEventHandler.HandleAsync(Event eventData, CancellationToken cancellationToken) - => eventData switch - { - TrackUpsertForRefreshEvent refresh => HandleAsync(refresh, cancellationToken), - TrackUpsertEvent upsert => HandleAsync(upsert, cancellationToken), - _ => Task.CompletedTask - }; + public Task HandleAsync(TrackUpsertEvent message, CancellationToken cancellationToken = default) + => ConsumerAsync(message); - public Task HandleAsync(TrackUpsertEvent @event, CancellationToken cancellationToken = default) - => ConsumerAsync(@event); - - public Task HandleAsync(TrackUpsertForRefreshEvent @event, CancellationToken cancellationToken = default) - => ConsumerAsync(@event); + public Task HandleAsync(TrackUpsertForRefreshEvent message, CancellationToken cancellationToken = default) + => ConsumerAsync(message); private async Task ConsumerAsync(TrackUpsertEvent @event) { @@ -107,7 +98,7 @@ public class TrackUpsertEventHandler( { var subEvent = nextEvent.DeepCopy(); subEvent.OrderIdentifiers = subOrderIds.ToArray(); - await eventBus.PublishAsync(subEvent); + await messagePublisher.PublishAsync(subEvent); } } } @@ -200,7 +191,7 @@ public class TrackUpsertEventHandler( // 如果存在轨迹标记,则触发订单pod拉取 if (!string.IsNullOrWhiteSpace(trackContent.TrackFlagId)) { - await eventBus.PublishAsync(new OrderPodPullEvent + await messagePublisher.PublishAsync(new OrderPodPullEvent { AppKey = @event.AppKey, OrderIdEsIdDict = insertTracks.ToDictionary(x => x.OrderId, y => y.Id), @@ -213,7 +204,7 @@ public class TrackUpsertEventHandler( await TrackChangePublicTopicAsync(trackContent, trackChangeEtos, true); // 触发订单主表更新事件(异步) - await eventBus.PublishAsync(new TrackChangeAfterUpdateOrderEvent + await messagePublisher.PublishAsync(new TrackChangeAfterUpdateOrderEvent { OrderIds = canNextOrderIds.ToArray(), IsCompleted = trackContent.IsCompleted, @@ -248,7 +239,7 @@ public class TrackUpsertEventHandler( ForcedPush = @event.ForcedPush, IsToMq = (trackContent.IsToMq || @event.IsToMq) }; - await eventBus.PublishAsync(trackPushEvent); + await messagePublisher.PublishAsync(trackPushEvent); } private async Task> UpsertTrackAsync( diff --git a/src/TrackCenter.Application/Rabbit/IRabbitHandler.cs b/src/TrackCenter.Application/Rabbit/IRabbitHandler.cs deleted file mode 100644 index 19635f18..00000000 --- a/src/TrackCenter.Application/Rabbit/IRabbitHandler.cs +++ /dev/null @@ -1,10 +0,0 @@ -using RabbitMQ.Client.Events; - -namespace TrackCenter.Application.Rabbit; - -public interface IRabbitHandler -{ - bool Enable(ConsumeOptions options); - - Task Handle(BasicDeliverEventArgs args); -} diff --git a/src/TrackCenter.Application/Rabbit/RabbitClient.cs b/src/TrackCenter.Application/Rabbit/RabbitClient.cs deleted file mode 100644 index ac0ebdae..00000000 --- a/src/TrackCenter.Application/Rabbit/RabbitClient.cs +++ /dev/null @@ -1,166 +0,0 @@ -using Fake.RabbitMQ; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using RabbitMQ.Client; -using RabbitMQ.Client.Events; - -namespace TrackCenter.Application.Rabbit; - -public class RabbitClient( - IRabbitMqChannelPool channelPool, - IServiceScopeFactory serviceScopeFactory, - ILogger logger, - IOptions options) : ISingletonDependency, IHostedService -{ - public void Subscribe(ConsumeOptions consumeOptions) - { - using var channelAccessor = channelPool.Acquire(consumeOptions.Queue); - - if (!channelAccessor.IsNew) return; - var channel = channelAccessor.Channel; - var decl = new DefaultDeclaration(channel); - - consumeOptions.Declaration.Invoke(decl); - - if (consumeOptions.FetchCount > 0) - { - channel.BasicQos(0, consumeOptions.FetchCount, false); - } - - var consumer = new AsyncEventingBasicConsumer(channel); - consumer.Received += (model, ea) => - { - _ = Task.Run(async () => - { - try - { - await using var scope = serviceScopeFactory.CreateAsyncScope(); - foreach (var handler in scope.ServiceProvider.GetServices()) - { - if (handler.Enable(consumeOptions)) - { - await handler.Handle(ea); - } - } - channel.BasicAck(ea.DeliveryTag, false); - } - catch (Exception ex) - { - logger.LogError($"rabbit on queue({consumeOptions.Queue}) received error: {ex}"); - channel.BasicNack(ea.DeliveryTag, false, consumeOptions.FailedRequeue); - } - }); - - return Task.CompletedTask; - }; - - channel.CallbackException += (sender, args) => - { - logger.LogError(args.Exception, "RabbitMQ channel exception"); - }; - - channel.BasicConsume(queue: consumeOptions.Queue, - autoAck: false, - consumer: consumer); - } - - public void Publish(string exchange, string routingKey, byte[] data, Action? options = null) - { - using var channelAccessor = channelPool.Acquire(routingKey); - var props = channelAccessor.Channel.CreateBasicProperties(); - options?.Invoke(props); - channelAccessor.Channel.BasicPublish(exchange, routingKey, props, data); - } - - public void PublishByConfirmSelect( - string exchange, - string routingKey, - byte[] data, - Action? options = null - ) - { - using var activity = RabbitInstrumentation.ActivitySource.StartActivity("/" + exchange + "/" + routingKey); - activity?.SetTag("kind", "publish"); - using var channelAccessor = channelPool.Acquire(routingKey); - var basicProperties = channelAccessor.Channel.CreateBasicProperties(); - - // 配置属性 - if (options != null) - options(basicProperties); - var model = channelAccessor.Channel; - - // 启用发布确认 - model.ConfirmSelect(); - var readOnlyMemory = (ReadOnlyMemory) data; - model.BasicPublish(exchange, routingKey, basicProperties, readOnlyMemory); - model.WaitForConfirmsOrDie(); - } - - public void PublishByConfirmSelect( - string exchange, - string routingKey, - IEnumerable datas, - Action? options = null - ) - { - using var activity = RabbitInstrumentation.ActivitySource.StartActivity("/" + exchange + "/" + routingKey); - activity?.SetTag("kind", "publish"); - using var channelAccessor = channelPool.Acquire(routingKey); - var basicProperties = channelAccessor.Channel.CreateBasicProperties(); - - // 配置属性 - if (options != null) - options(basicProperties); - var model = channelAccessor.Channel; - - // 启用发布确认 - model.ConfirmSelect(); - foreach (var data in datas) - { - var readOnlyMemory = (ReadOnlyMemory) data; - model.BasicPublish(exchange, routingKey, basicProperties, readOnlyMemory); - } - - model.WaitForConfirmsOrDie(); - } - - public void UnSubscribe(string queueName, string exchange, string routingKey, bool deleteQueue = false) - { - logger.LogInformation( - $"UnSubscribe queue: {queueName} exchange: {exchange} routingKey: {routingKey} deleteQueue: {deleteQueue}"); - using var channelAccessor = channelPool.Acquire(queueName); - if (deleteQueue) - { - var passive = channelAccessor.Channel.QueueDeclarePassive(queueName); - logger.LogInformation($"Queue {queueName} exists, deleting... {passive.MessageCount} messages in queue"); - channelAccessor.Channel.QueueDelete(queueName); - } - - channelPool.Release(queueName); - } - - public Task StartAsync(CancellationToken cancellationToken) - { - if (options.Value.Declarations.Count > 0) - { - using var channelAccessor = channelPool.Acquire(); - var channel = channelAccessor.Channel; - var decl = new DefaultDeclaration(channel); - options.Value.Declarations.ForEach(q => q.Invoke(decl)); - } - - foreach (var opt in options.Value.Consumes) - { - Subscribe(opt); - } - - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - channelPool.Dispose(); - return Task.CompletedTask; - } -} diff --git a/src/TrackCenter.Application/Rabbit/RabbitInstrumentation.cs b/src/TrackCenter.Application/Rabbit/RabbitInstrumentation.cs deleted file mode 100644 index 2afdc420..00000000 --- a/src/TrackCenter.Application/Rabbit/RabbitInstrumentation.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Diagnostics; -using System.Diagnostics.Metrics; - -namespace TrackCenter.Application.Rabbit; - -public class RabbitInstrumentation -{ - public const string MeterName = "Fake.Rabbit.Meter"; - public const string ActivitySourceName = "Fake.Rabbit.ActivitySource"; - - static RabbitInstrumentation() - { - string version = typeof (RabbitInstrumentation).Assembly.GetName().Version?.ToString(); - Meter = new Meter(MeterName, version); - ActivitySource = new ActivitySource(ActivitySourceName, version); - } - - public static Meter Meter { get; } - - public static ActivitySource ActivitySource { get; } -} diff --git a/src/TrackCenter.Application/Rabbit/RabbitOptions.cs b/src/TrackCenter.Application/Rabbit/RabbitOptions.cs deleted file mode 100644 index 258f5ea7..00000000 --- a/src/TrackCenter.Application/Rabbit/RabbitOptions.cs +++ /dev/null @@ -1,84 +0,0 @@ -using RabbitMQ.Client; - -namespace TrackCenter.Application.Rabbit; - -public class RabbitOptions -{ - public List Consumes { get; set; } = new(); - - public List> Declarations { get; set; } = new(); -} - -public class ConsumeOptions -{ - /// - /// 队列名 - /// - public string Queue { get; set; } - - /// - /// 并行度 - /// - public ushort FetchCount { get; set; } = 1; - - /// - /// handle发生异常,是否重回队列 - /// - public bool FailedRequeue { get; set; } - - public Action Declaration { get; set; } -} - -public interface IDeclaration -{ - void QueueDeclare(string queue, bool durable, bool autoDelete = false, bool exclusive = false, - IDictionary arguments = null); - - void ExchangeDeclare(string exchange, string type, bool durable, bool autoDelete = false, - IDictionary arguments = null); - - void QueueBind(string queue, string exchange, string routingKey, - IDictionary arguments = null); -} - -public class DefaultDeclaration : IDeclaration -{ - private readonly IModel _chnl; - - // ReSharper disable once ConvertToPrimaryConstructor - public DefaultDeclaration(IModel chnl) - { - _chnl = chnl; - } - - public void QueueDeclare(string queue, bool durable, bool autoDelete = false, bool exclusive = false, - IDictionary arguments = null) - { - _chnl.QueueDeclare( - queue: queue, - durable: durable, - autoDelete: autoDelete, - exclusive: exclusive, - arguments: arguments); - } - - public void ExchangeDeclare(string exchange, string type, bool durable, bool autoDelete = false, - IDictionary arguments = null) - { - _chnl.ExchangeDeclare( - exchange: exchange, - type: type, - durable: durable, - autoDelete: autoDelete, - arguments: arguments); - } - - public void QueueBind(string queue, string exchange, string routingKey, IDictionary arguments) - { - _chnl.QueueBind( - queue: queue, - exchange: exchange, - routingKey: routingKey, - arguments: arguments); - } -} diff --git a/src/TrackCenter.Application/Services/Broadcasting/BroadcastingService.cs b/src/TrackCenter.Application/Services/Broadcasting/BroadcastingService.cs index 16468571..36c15a6d 100644 --- a/src/TrackCenter.Application/Services/Broadcasting/BroadcastingService.cs +++ b/src/TrackCenter.Application/Services/Broadcasting/BroadcastingService.cs @@ -1,74 +1,102 @@ using System.Text; +using Fake.RabbitMQ; using InterfaceForward.Domain.Shared.Helpers; +using RabbitMQ.Client; using TrackCenter.Application.Dtos.TrackPush; using TrackCenter.Application.Events; -using TrackCenter.Application.Rabbit; namespace TrackCenter.Application.Services.Broadcasting; /// -/// 广播服务 +/// 对外 Topic 广播(下游仍按 Newtonsoft PascalCase 契约消费,不经 Messaging 信封)。 /// -public class BroadcastingService : ITransientDependency +public class BroadcastingService(IRabbitMqChannelPool channelPool) : ITransientDependency { - private readonly RabbitClient _rabbitClient; - - public BroadcastingService(RabbitClient rabbitClient) + public void TrackChangePublicTopic(TrackChangeEto eto, string AppCode) { - _rabbitClient = rabbitClient; - } - - public void TrackChangePublicTopic(TrackChangeEto eto, string AppCode) - { - _rabbitClient.PublishByConfirmSelect( + PublishByConfirmSelect( GlobalConst.TrackChangeExchange, + ExchangeType.Topic, $"TrackChange.{AppCode}", Encoding.UTF8.GetBytes(eto.ToJson()), - prop => { prop.Persistent = true; } - ); + prop => { prop.Persistent = true; }); } /// /// 轨迹推送完成广播(批量) /// - /// - /// public void TrackPushCompletedPublicTopic(List list) { var data = list .Select(TrackPushRecordDtoToEvent) .Select(x => Encoding.UTF8.GetBytes(x.ToJson())); var log = list.First(); - _rabbitClient.PublishByConfirmSelect( + PublishByConfirmSelect( GlobalConst.TrackPushExchange, + ExchangeType.Topic, $"TrackPush.{log.AppKey}", data, - prop => { prop.Persistent = true; } - ); + prop => { prop.Persistent = true; }); } /// /// 轨迹推送完成广播 /// - /// - /// public void TrackPushCompletedPublicTopic(TrackPushRecordDto log) { var data = TrackPushRecordDtoToEvent(log); - _rabbitClient.PublishByConfirmSelect(GlobalConst.TrackPushExchange, $"TrackPush.{log.AppKey}", - Encoding.UTF8.GetBytes(data.ToJson()), prop => { prop.Persistent = true; }); + PublishByConfirmSelect( + GlobalConst.TrackPushExchange, + ExchangeType.Topic, + $"TrackPush.{log.AppKey}", + Encoding.UTF8.GetBytes(data.ToJson()), + prop => { prop.Persistent = true; }); } /// /// 轨迹推送失败广播 /// - /// public void TrackPushFailedPubilcTopic(TrackPushRecordDto log) { //暂时使用推送完成模型,后续可能会出现有区分度的模型 TrackPushCompletedPublicTopic(log); } + private void PublishByConfirmSelect( + string exchange, + string exchangeType, + string routingKey, + byte[] data, + Action? options = null) + { + using var channelAccessor = channelPool.Acquire(routingKey); + var channel = channelAccessor.Channel; + channel.ExchangeDeclare(exchange, exchangeType, durable: true); + var props = channel.CreateBasicProperties(); + options?.Invoke(props); + channel.ConfirmSelect(); + channel.BasicPublish(exchange, routingKey, props, data); + channel.WaitForConfirmsOrDie(); + } + + private void PublishByConfirmSelect( + string exchange, + string exchangeType, + string routingKey, + IEnumerable datas, + Action? options = null) + { + using var channelAccessor = channelPool.Acquire(routingKey); + var channel = channelAccessor.Channel; + channel.ExchangeDeclare(exchange, exchangeType, durable: true); + var props = channel.CreateBasicProperties(); + options?.Invoke(props); + channel.ConfirmSelect(); + foreach (var data in datas) + channel.BasicPublish(exchange, routingKey, props, data); + channel.WaitForConfirmsOrDie(); + } + private static TrackPushCompletedEvent TrackPushRecordDtoToEvent(TrackPushRecordDto log) { return new TrackPushCompletedEvent diff --git a/src/TrackCenter.Application/Services/ProvideServices/OrderService.Link.cs b/src/TrackCenter.Application/Services/ProvideServices/OrderService.Link.cs index 3371500e..89387578 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/OrderService.Link.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/OrderService.Link.cs @@ -1,5 +1,5 @@ using System.Data; -using Fake.EventBus.Distributed; +using Fake.Messaging; using Fake.UnitOfWork; using TrackCenter.Application.Dtos.ProvideServices; using TrackCenter.Application.Events; @@ -13,7 +13,7 @@ namespace TrackCenter.Application.Services.ProvideServices; /// public partial class OrderService { - private readonly IDistributedEventBus _eventBus = eventBus; + private readonly IMessagePublisher _messagePublisher = messagePublisher; private readonly ITrackDetailsEsRepository _trackDetailsEsRepository = trackDetailsEsRepository; /// @@ -130,7 +130,7 @@ public partial class OrderService IsAdd = true // 存在则不新增 }; - await _eventBus.PublishAsync(fillTrackEvent); + await _messagePublisher.PublishAsync(fillTrackEvent); } } diff --git a/src/TrackCenter.Application/Services/ProvideServices/OrderService.cs b/src/TrackCenter.Application/Services/ProvideServices/OrderService.cs index 9211d0e2..6ccfa095 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/OrderService.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/OrderService.cs @@ -1,4 +1,4 @@ -using Fake.EventBus.Distributed; +using Fake.Messaging; using TrackCenter.Application.Dtos.ProvideServices; using TrackCenter.Domain.Aggregates.OrderAggregate; using TrackCenter.Domain.Aggregates.TrackDetailsAggregate; @@ -17,7 +17,7 @@ public partial class OrderService( IOrderRepository orderRepository, IOrderOperationRecordEsRepository orderOperationRecordEsRepository, ITrackPullConfigRepository trackPullConfigRepository, - IDistributedEventBus eventBus, + IMessagePublisher messagePublisher, ITrackDetailsEsRepository trackDetailsEsRepository, IServiceProvider serviceProvider) : ApplicationServiceBase diff --git a/src/TrackCenter.Application/Services/ProvideServices/TrackPushService.cs b/src/TrackCenter.Application/Services/ProvideServices/TrackPushService.cs index f371e4ba..fe595f5d 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/TrackPushService.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/TrackPushService.cs @@ -1,5 +1,5 @@ using System.Data; -using Fake.EventBus.Distributed; +using Fake.Messaging; using Fake.UnitOfWork; using TrackCenter.Application.Dtos.ProvideServices; using TrackCenter.Application.Dtos.TrackOrder; @@ -20,20 +20,20 @@ namespace TrackCenter.Application.Services.ProvideServices; [Route("/ProviderService")] public class TrackPushService : ApplicationServiceBase { - private readonly IDistributedEventBus _eventBus; + private readonly IMessagePublisher _messagePublisher; private readonly IOrderRepository _orderRepository; private readonly ITrackPushConfigRepository _trackPushConfigRepository; private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository; private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; public TrackPushService(IOrderRepository orderRepository - , IDistributedEventBus eventBus + , IMessagePublisher messagePublisher , ITrackPushRecordEsRepository trackPushRecordEsRepository , ITrackPushConfigRepository trackPushConfigRepository, ITrackDetailsEsRepository trackDetailsEsRepository) { _orderRepository = orderRepository; - _eventBus = eventBus; + _messagePublisher = messagePublisher; _trackPushRecordEsRepository = trackPushRecordEsRepository; _trackPushConfigRepository = trackPushConfigRepository; _trackDetailsEsRepository = trackDetailsEsRepository; @@ -155,7 +155,7 @@ public class TrackPushService : ApplicationServiceBase } }; - await _eventBus.PublishAsync(trackPushEvent); + await _messagePublisher.PublishAsync(trackPushEvent); pushedOrderNos.Add(order.OrderNo); } diff --git a/src/TrackCenter.Application/Services/ProvideServices/TrackService.cs b/src/TrackCenter.Application/Services/ProvideServices/TrackService.cs index 0a4d22e0..fba94972 100644 --- a/src/TrackCenter.Application/Services/ProvideServices/TrackService.cs +++ b/src/TrackCenter.Application/Services/ProvideServices/TrackService.cs @@ -1,5 +1,5 @@ using System.Data; -using Fake.EventBus.Distributed; +using Fake.Messaging; using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; using TrackCenter.Application.Dtos.ProvideServices; @@ -19,7 +19,7 @@ namespace TrackCenter.Application.Services.ProvideServices; [Route("/ProviderService")] public partial class TrackService( IOrderRepository orderRepository, - IDistributedEventBus eventBus, + IMessagePublisher messagePublisher, ITrackDetailsEsRepository trackDetailsEsRepository, ITrackContentRepository trackContentRepository) : ApplicationServiceBase @@ -90,7 +90,7 @@ public partial class TrackService( } // 删除轨迹(异步) - await eventBus.PublishAsync(new TrackDeleteEvent + await messagePublisher.PublishAsync(new TrackDeleteEvent { EsIds = esIds, OrderIds = new[] { orderId }, @@ -165,7 +165,7 @@ public partial class TrackService( AppKey = input.AppKey, OperationMan = CurrentUser.UserName }; - await eventBus.PublishAsync(@event); + await messagePublisher.PublishAsync(@event); } /// @@ -219,7 +219,7 @@ public partial class TrackService( } }; @event.OperationMan = CurrentUser.UserName; - await eventBus.PublishAsync(@event); + await messagePublisher.PublishAsync(@event); } /// @@ -292,7 +292,7 @@ public partial class TrackService( ForcedPush = input.ForcedPush, IsToMq = input.IsToMq, }; - await eventBus.PublishAsync(@event); + await messagePublisher.PublishAsync(@event); } } diff --git a/src/TrackCenter.Application/Services/Warning/ReturnWarningService.cs b/src/TrackCenter.Application/Services/Warning/ReturnWarningService.cs index 368d0c6d..c420c49f 100644 --- a/src/TrackCenter.Application/Services/Warning/ReturnWarningService.cs +++ b/src/TrackCenter.Application/Services/Warning/ReturnWarningService.cs @@ -1,5 +1,5 @@ using System.Data; -using Fake.EventBus.Distributed; +using Fake.Messaging; using Fake.Domain.Dtos; using Fake.UnitOfWork; using InterfaceForward.Domain.Shared.Helpers; @@ -27,7 +27,7 @@ public class ReturnWarningService : ApplicationServiceBase private readonly IReturnWarningHandler _returnWarningHandler; private readonly IWarningRuleRepository _warningRuleRepository; private readonly IWarningDetailsEsRepository _warningDetailsEsRepository; - private readonly IDistributedEventBus _eventBus; + private readonly IMessagePublisher _messagePublisher; private readonly TrackStatusNameDictCache _trackStatusNameDictCache; private readonly AppNameDictCache _appNameDictCache; @@ -36,7 +36,7 @@ public class ReturnWarningService : ApplicationServiceBase IReturnWarningHandler returnWarningHandler, IWarningRuleRepository warningRuleRepository, IWarningDetailsEsRepository warningDetailsEsRepository, - IDistributedEventBus eventBus, + IMessagePublisher messagePublisher, TrackStatusNameDictCache trackStatusNameDictCache, AppNameDictCache appNameDictCache ) @@ -45,7 +45,7 @@ public class ReturnWarningService : ApplicationServiceBase _returnWarningHandler = returnWarningHandler; _warningRuleRepository = warningRuleRepository; _warningDetailsEsRepository = warningDetailsEsRepository; - _eventBus = eventBus; + _messagePublisher = messagePublisher; _trackStatusNameDictCache = trackStatusNameDictCache; _appNameDictCache = appNameDictCache; } @@ -279,7 +279,7 @@ public class ReturnWarningService : ApplicationServiceBase } }; - await _eventBus.PublishAsync(trackPushEvent); + await _messagePublisher.PublishAsync(trackPushEvent); } return $"即将进行{filtered.Count}个回传推送!"; diff --git a/src/TrackCenter.Application/TrackCenter.Application.csproj b/src/TrackCenter.Application/TrackCenter.Application.csproj index ccab7abc..43dd17cb 100644 --- a/src/TrackCenter.Application/TrackCenter.Application.csproj +++ b/src/TrackCenter.Application/TrackCenter.Application.csproj @@ -9,8 +9,7 @@ - - + diff --git a/src/TrackCenter.Application/TrackCenterApplicationModule.cs b/src/TrackCenter.Application/TrackCenterApplicationModule.cs index 4c0de9ef..dd7535d1 100644 --- a/src/TrackCenter.Application/TrackCenterApplicationModule.cs +++ b/src/TrackCenter.Application/TrackCenterApplicationModule.cs @@ -1,28 +1,26 @@ using System.Diagnostics; using System.Net; using Fake; -using Fake.EventBus.RabbitMQ; +using Fake.Messaging; +using Fake.Messaging.RabbitMQ; using Fake.Modularity; using Fake.ObjectMapping.AutoMapper; using Fake.ObjectStorage; -using Fake.RabbitMQ; using FreeRedis; using Hangfire; using Hangfire.Redis.StackExchange; using InterfaceForward.Domain.Shared.Helpers; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using RabbitMQ.Client; -using TrackCenter.Application.Kafka; using TrackCenter.Application.HostServices; +using TrackCenter.Application.Kafka; +using TrackCenter.Application.Messaging; using TrackCenter.Application.Options; -using TrackCenter.Application.Rabbit; namespace TrackCenter.Application; -[DependsOn(typeof(FakeRabbitMqModule))] [DependsOn(typeof(FakeObjectMappingAutoMapperModule))] -[DependsOn(typeof(FakeEventBusRabbitMqModule))] +[DependsOn(typeof(FakeMessagingRabbitMqModule))] [DependsOn(typeof(FakeObjectStorageTencentCosModule))] [DependsOn(typeof(TrackCenterDomainModule))] public class TrackCenterApplicationModule : FakeModule @@ -36,50 +34,27 @@ public class TrackCenterApplicationModule : FakeModule options.ScanProfiles(); }); + // Messaging:独立队列;PrefetchCount=0 → ProcessorCount;接口通可按 TrackApp:TrackRefreshFetchCount 覆盖 + context.Services.Configure(configuration.GetSection(MessagingOptions.SectionName)); + context.Services.Configure(o => + { + configuration.GetSection(RabbitMessageOptions.SectionName).Bind(o); + + var refreshFetch = configuration.GetValue("TrackApp:TrackRefreshFetchCount"); + if (refreshFetch > 0) + { + o.Handlers[nameof(TrackRefreshEventHandler)] = + new RabbitMessageHandlerOptions { PrefetchCount = refreshFetch }; + o.Handlers[nameof(TrackPushCompletedEventHandler)] = + new RabbitMessageHandlerOptions { PrefetchCount = refreshFetch }; + } + }); + var redisOptions = configuration.GetSection("Redis").Get(); if (redisOptions == null) throw new FakeException("未找到Redis相关配置,请检查配置文件中是否包含名为Redis的节点"); RedisHelper.Init(redisOptions, showLogInfo: Debugger.IsAttached); - context.Services.AddHostedService(); - context.Services.Configure(options => - { - options.Declarations = new List>() - { - o => o.ExchangeDeclare(GlobalConst.TrackChangeExchange, ExchangeType.Topic, true), - o => o.ExchangeDeclare(GlobalConst.TrackPushExchange, ExchangeType.Topic, true) - }; - options.Consumes = new List - { - new() - { - Queue = GlobalConst.TrackRefreshSubscribe, - FetchCount = configuration.GetValue("TrackApp:TrackRefreshFetchCount"), - FailedRequeue = false, - Declaration = o => - { - o.ExchangeDeclare(GlobalConst.InterfaceRelayExchange, ExchangeType.Direct, true); - o.QueueDeclare(GlobalConst.TrackRefreshSubscribe, true); - o.QueueBind(GlobalConst.TrackRefreshSubscribe, GlobalConst.InterfaceRelayExchange, - GlobalConst.TrackRefreshSubscribe); - } - }, - new() - { - Queue = GlobalConst.TrackPushCompletedSubscribe, - FetchCount = configuration.GetValue("TrackApp:TrackRefreshFetchCount"), - FailedRequeue = false, - Declaration = o => - { - o.ExchangeDeclare(GlobalConst.InterfaceRelayExchange, ExchangeType.Direct, true); - o.QueueDeclare(GlobalConst.TrackPushCompletedSubscribe, true); - o.QueueBind(GlobalConst.TrackPushCompletedSubscribe, GlobalConst.InterfaceRelayExchange, - GlobalConst.TrackPushCompletedSubscribe); - } - } - }; - }); - context.Services.Configure(configuration.GetSection("TrackApp")); context.Services.Configure( configuration.GetSection("InterfaceRelayParamsConfig")); -- 2.45.2