diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Attributes/TimedAttribute.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Attributes/TimedAttribute.cs new file mode 100644 index 00000000..1b8edfd3 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Attributes/TimedAttribute.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.WarehouseMgr.Entities.Attributes +{ + /// + ///定时任务特性 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class TimedAttribute : Attribute + { + public string Name { get; set; } + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/Inputs/NotifyMessage.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/Inputs/NotifyMessage.cs new file mode 100644 index 00000000..0e4362e2 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/Inputs/NotifyMessage.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.WarehouseMgr.Entities.Dto.Inputs +{ + /// + /// 通知消息类 + /// + public class NotifyMessage + { + /// + /// 任务名称 + /// + public string TaskName { get; set; } = string.Empty; + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/ITaskMessageNotify.cs b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/ITaskMessageNotify.cs new file mode 100644 index 00000000..1b6eb44a --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/ITaskMessageNotify.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Channels; +using System.Threading.Tasks; +using Tnb.WarehouseMgr.Entities.Dto.Inputs; + +namespace Tnb.WarehouseMgr.Interfaces +{ + /// + /// 任务消息通知接口 + /// + public interface ITaskMessageNotify + { + ChannelReader Reader { get; } + ChannelWriter Writer { get; } + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr/Filters/NotifyFilterAttribute.cs b/WarehouseMgr/Tnb.WarehouseMgr/Filters/NotifyFilterAttribute.cs new file mode 100644 index 00000000..059efe54 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr/Filters/NotifyFilterAttribute.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; +using Tnb.WarehouseMgr.Entities.Dto.Inputs; +using Tnb.WarehouseMgr.Interfaces; + +namespace Tnb.WarehouseMgr.Filters +{ + public class NotifyFilterAttribute : ActionFilterAttribute + { + + public override async void OnActionExecuted(ActionExecutedContext context) + { + var actionName = context.ActionDescriptor.RouteValues["action"]!; + var taskMessageNotify = context.HttpContext.RequestServices.GetRequiredService(); + if (taskMessageNotify != null) + { + NotifyMessage message = new() { TaskName = actionName }; + await taskMessageNotify.Writer.WriteAsync(message); + } + } + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr/TaskMesageNotify.cs b/WarehouseMgr/Tnb.WarehouseMgr/TaskMesageNotify.cs new file mode 100644 index 00000000..6e0b6cc1 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr/TaskMesageNotify.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Channels; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Tnb.WarehouseMgr.Entities.Dto.Inputs; +using Tnb.WarehouseMgr.Interfaces; + +namespace Tnb.WarehouseMgr +{ + /// + /// 任务消息通知 + /// + public class TaskMesageNotify : ITaskMessageNotify + { + private readonly Channel _channel = Channel.CreateUnbounded(); + + public ChannelReader Reader => _channel.Reader; + public ChannelWriter Writer => _channel.Writer; + + } + + + //public static class TaskMesageNotify + //{ + // private static readonly Channel _channel = Channel.CreateUnbounded(); + + + // public static ChannelReader Reader => _channel.Reader; + // public static ChannelWriter Writer => _channel.Writer; + + + //} + + public static class TaskMessageNotifyExtensions + { + public static IServiceCollection AddTaskMessageNotify(this IServiceCollection services) + { + services.AddSingleton(); + return services; + } + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr/TimedTaskBackgroundService.cs b/WarehouseMgr/Tnb.WarehouseMgr/TimedTaskBackgroundService.cs index 55ba81df..4e999c48 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/TimedTaskBackgroundService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/TimedTaskBackgroundService.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; using Aop.Api.Domain; @@ -17,9 +20,12 @@ using JNPF.Message.Interfaces.Message; using JNPF.Systems.Entitys.System; using Mapster; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; +using Natasha.CSharp; using Tnb.Common.Extension; +using Tnb.WarehouseMgr.Entities.Attributes; using Tnb.WarehouseMgr.Entities.Dto.Inputs; using Tnb.WarehouseMgr.Entities.Exceptions; using Tnb.WarehouseMgr.Interfaces; @@ -33,27 +39,58 @@ namespace Tnb.WarehouseMgr public class TimedTaskBackgroundService : BackgroundService { private IEventPublisher _eventPublisher = default!; + private readonly IServiceProvider _serviceProvider; + private static Dictionary> _timedFuncMap = new(StringComparer.OrdinalIgnoreCase); + static TimedTaskBackgroundService() + { + _timedFuncMap = App.EffectiveTypes.AsParallel().Where(t => !t.Namespace.IsNullOrWhiteSpace() && t.Namespace.Contains("Tnb.WarehouseMgr")).SelectMany(t => t.GetMethods()) + .Where(m => m.GetCustomAttribute() != null) + .ToDictionary(x => x.Name, x => + (Func)Delegate.CreateDelegate(typeof(Func), App.GetService(x.DeclaringType), x)); + } + public TimedTaskBackgroundService(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } - protected override Task ExecuteAsync(CancellationToken stoppingToken) => Task.Run(() => + protected override Task ExecuteAsync(CancellationToken stoppingToken) => Task.Run(async () => { - _eventPublisher = App.GetRequiredService(); - List toUserIds = new List() { "25398501929509" }; - //生成任务执行 - CancellationTokenSource genTaskCTS = new(); - CancellationTokenSource kittingOutAddCts = new(); - CancellationTokenSource kittingOutShippedCts = new(); - CancellationTokenSource setSortingCts = new(); - var wareHouseService = App.GetRequiredService(); - TimedTask(cts => wareHouseService.GenTaskExecute(cts), genTaskCTS, toUserIds); - //齐套出库 + var channelReader = _serviceProvider.GetRequiredService().Reader; - var kittingOutService = App.GetRequiredService(); - TimedTask(cts => kittingOutService.KittingOutByAdd(cts), kittingOutAddCts, toUserIds); - TimedTask(cts => kittingOutService.KittingOutByIsToBeShipped(cts), kittingOutShippedCts, toUserIds); - //齐套分拣 - var setSortingService = App.GetRequiredService(); - TimedTask(cts => setSortingService.PackSortingByAdd(cts), setSortingCts, toUserIds); + CancellationTokenSource? cts = new(); + + while (channelReader != null && await channelReader.WaitToReadAsync()) + { + while (channelReader.TryRead(out var message)) + { + if (_timedFuncMap.ContainsKey(message.TaskName)) + { + await _timedFuncMap[message.TaskName].Invoke(cts); + } + } + } + + #region 定时 + //_eventPublisher = App.GetRequiredService(); + //List toUserIds = new List() { "25398501929509" }; + ////生成任务执行 + //CancellationTokenSource genTaskCTS = new(); + //CancellationTokenSource kittingOutAddCts = new(); + //CancellationTokenSource kittingOutShippedCts = new(); + //CancellationTokenSource setSortingCts = new(); + + //var wareHouseService = App.GetRequiredService(); + //TimedTask(cts => wareHouseService.GenTaskExecute(cts), genTaskCTS, toUserIds); + ////齐套出库 + + //var kittingOutService = App.GetRequiredService(); + //TimedTask(cts => kittingOutService.KittingOutByAdd(cts), kittingOutAddCts, toUserIds); + //TimedTask(cts => kittingOutService.KittingOutByIsToBeShipped(cts), kittingOutShippedCts, toUserIds); + ////齐套分拣 + //var setSortingService = App.GetRequiredService(); + //TimedTask(cts => setSortingService.PackSortingByAdd(cts), setSortingCts, toUserIds); + #endregion }, stoppingToken); private Task TimedTask(Func action, CancellationTokenSource cts, List? toUserIds = default) diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs b/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs index 67d3f20b..f951f627 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs @@ -42,6 +42,7 @@ using Tnb.BasicData.Entities.Enums; using Tnb.Common.Extension; using Tnb.Common.Utils; using Tnb.WarehouseMgr.Entities; +using Tnb.WarehouseMgr.Entities.Attributes; using Tnb.WarehouseMgr.Entities.Configs; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Dto; @@ -222,16 +223,16 @@ namespace Tnb.WarehouseMgr /// 生成任务执行 /// /// - [HttpPost] + [HttpPost, Timed(Name = nameof(IWareHouseService.GenTaskExecute))] public async Task GenTaskExecute(CancellationTokenSource? cts = default) { Stopwatch sw = Stopwatch.StartNew(); CancellationTokenSource agvCts = new(); //获取用户登录令牌 - var aToken = await _cacheManager.GetAsync("AsscessToken"); - if (aToken.IsNullOrWhiteSpace()) return; - var curUser = await GetUserIdentity(aToken); + //var aToken = await _cacheManager.GetAsync("AsscessToken"); + //if (aToken.IsNullOrWhiteSpace()) return; + //var curUser = await GetUserIdentity(aToken); var db = _db.CopyNew(); try @@ -239,7 +240,7 @@ namespace Tnb.WarehouseMgr //获取所有未下发的预任务申请 var preTasks = await db.Queryable().InnerJoin((a, b) => a.startlocation_id == b.location_id && a.carry_id == b.id) .InnerJoin((a, b, c) => a.area_id == c.id) - .Where(a => a.status == WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID) + .Where(a => a.status == WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID && !string.IsNullOrWhiteSpace(a.startlocation_id)) .OrderBy(a => new { priority = SqlFunc.Desc(a.priority), a.bill_code }) .Select((a, b, c) => new WmsPretaskH { @@ -379,18 +380,9 @@ namespace Tnb.WarehouseMgr catch (Exception ex) { Log.Error("生成预任务执行时出现错误", ex); - var opts = curUser.FindFirst(ClaimConst.CONNECTIONCONFIG)?.Value; - - TimedTaskErrorInfo ei = new() - { - RequestURL = App.HttpContext?.Request?.Path, - RequestMethod = App.HttpContext?.Request?.Method, - userIdentity = curUser, - }; - var timedTaskEx = ex.ToTimedTaskException(ei); await db.Ado.RollbackTranAsync(); cts?.Cancel(); - throw timedTaskEx; + throw; } finally { @@ -531,11 +523,15 @@ namespace Tnb.WarehouseMgr locIts.Add(loc); } + await _db.Updateable(carryIts).UpdateColumns(it => new { it.is_lock, it.location_id, it.location_code }).ExecuteCommandAsync(); + //更新条码的库位和仓库信息 - await _db.Updateable(carryCodeIts).UpdateColumns(it => new { it.warehouse_id, it.location_id, it.location_code }).Where(it => multiList.Select(x => x.carry_id).Contains(it.carry_id)).ExecuteCommandAsync(); + var carryIdItor = multiList.Select(x => x.carry_id); + await _db.Updateable(carryCodeIts).UpdateColumns(it => new { it.warehouse_id, it.location_id, it.location_code }).Where(it => it.carry_id.In(carryIdItor)).ExecuteCommandAsync(); //更新库位信息,使用状态为 使用,锁定状态为未锁定 - await _db.Updateable(locIts).UpdateColumns(it => new { it.is_use, it.is_lock }).Where(it => multiList.Select(x => x.endlocation_id).Contains(it.id)).ExecuteCommandAsync(); + var locIdItor = multiList.Select(x => x.endlocation_id); + await _db.Updateable(locIts).UpdateColumns(it => new { it.is_use, it.is_lock }).Where(it => it.id.In(locIdItor)).ExecuteCommandAsync(); //更新业务主表的单据状态 foreach (var dt in disTasks) { diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WmsEmptyInstockService.cs b/WarehouseMgr/Tnb.WarehouseMgr/WmsEmptyInstockService.cs index 01d00f36..f9b5abd4 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/WmsEmptyInstockService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/WmsEmptyInstockService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading.Channels; using System.Threading.Tasks; using JNPF.Common.Contracts; using JNPF.Common.Core.Manager; @@ -24,6 +25,7 @@ using Tnb.WarehouseMgr.Entities.Attributes; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Dto; using Tnb.WarehouseMgr.Entities.Dto.Inputs; +using Tnb.WarehouseMgr.Filters; using Tnb.WarehouseMgr.Interfaces; namespace Tnb.WarehouseMgr @@ -44,13 +46,16 @@ namespace Tnb.WarehouseMgr private readonly IWareHouseService _wareHouseService; private readonly IBillRullService _billRullService; private readonly IUserManager _userManager; + private readonly ChannelWriter _channelWriter; public WmsEmptyInstockService( ISqlSugarRepository repository, IRunService runService, IVisualDevService visualDevService, IWareHouseService wareHouseService, IUserManager userManager, - IBillRullService billRullService) + IBillRullService billRullService, + ITaskMessageNotify taskMesageNotify + ) { _db = repository.AsSugarClient(); _runService = runService; @@ -58,9 +63,9 @@ namespace Tnb.WarehouseMgr _wareHouseService = wareHouseService; _userManager = userManager; _billRullService = billRullService; + _channelWriter = taskMesageNotify.Writer; OverideFuncs.CreateAsync = WmsEmptyIn; } - private async Task WmsEmptyIn(VisualDevModelDataCrInput input) { @@ -159,6 +164,7 @@ namespace Tnb.WarehouseMgr await _wareHouseService.GenInStockTaskHandleAfter(preTaskUpInput, it => new WmsCarryH { is_lock = 1, location_id = preTaskUpInput.CarryStartLocationId, location_code = preTaskUpInput.CarryStartLocationCode }, it => new BasLocation { is_lock = 1 }); + } else { @@ -179,6 +185,12 @@ namespace Tnb.WarehouseMgr await _db.Ado.RollbackTranAsync(); throw; } + finally + { + //向队列写入消息 + NotifyMessage message = new() { TaskName = nameof(IWareHouseService.GenTaskExecute) }; + await _channelWriter.WriteAsync(message); + } return Task.FromResult(true); } /// diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WmsSetSortingService.cs b/WarehouseMgr/Tnb.WarehouseMgr/WmsSetSortingService.cs index b63baf28..e519dfa0 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/WmsSetSortingService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/WmsSetSortingService.cs @@ -58,7 +58,7 @@ namespace Tnb.WarehouseMgr /// 齐套分拣(新增状态) /// /// - [HttpPost] + [HttpPost, Timed(Name = nameof(PackSortingByAdd))] public async Task PackSortingByAdd(CancellationTokenSource? cts = default) { var aToken = await _cacheManager.GetAsync("AccessToken"); diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WmskittingOutService.cs b/WarehouseMgr/Tnb.WarehouseMgr/WmskittingOutService.cs index 2e8fd185..7b603c0f 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/WmskittingOutService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/WmskittingOutService.cs @@ -75,7 +75,7 @@ namespace Tnb.WarehouseMgr /// 齐套出库(新增状态) /// /// - [HttpPost] + [HttpPost, Timed(Name = nameof(KittingOutByAdd))] public async Task KittingOutByAdd(CancellationTokenSource? cts = default) { var aToken = await _cacheManager.GetAsync("AsscessToken"); @@ -163,7 +163,7 @@ namespace Tnb.WarehouseMgr } catch (Exception ex) { - JNPF.Logging.Log.Error("齐套出库,新增时出现错误", ex); + Log.Error("齐套出库,新增时出现错误", ex); await curDb.Ado.RollbackTranAsync(); TimedTaskErrorInfo ei = new() { @@ -175,12 +175,16 @@ namespace Tnb.WarehouseMgr cts?.Cancel(); throw timedTaskEx; } + finally + { + + } } /// /// 齐套出库,(待配送状态) /// /// - [HttpPost] + [HttpPost, Timed(Name = nameof(KittingOutByIsToBeShipped))] public async Task KittingOutByIsToBeShipped(CancellationTokenSource? cts = default) { var aToken = await _cacheManager.GetAsync("AsscessToken"); @@ -272,7 +276,7 @@ namespace Tnb.WarehouseMgr } catch (Exception ex) { - JNPF.Logging.Log.Error("齐套出库,待配送时出现错误", ex); + Log.Error("齐套出库,待配送时出现错误", ex); TimedTaskErrorInfo ei = new() { RequestURL = App.HttpContext?.Request?.Path, diff --git a/apihost/Tnb.API.Entry/Startup.cs b/apihost/Tnb.API.Entry/Startup.cs index dd5e6ed7..2d5ed531 100644 --- a/apihost/Tnb.API.Entry/Startup.cs +++ b/apihost/Tnb.API.Entry/Startup.cs @@ -62,7 +62,8 @@ public class Startup : AppStartup .AddSenparcWeixinServices(App.Configuration); // Senparc.Weixin 注册(如果使用Senparc.Weixin SDK则添加) services.AddOverideVisualDev(); - + //注册任务消息通知 added by ly on 20230814 + services.AddTaskMessageNotify(); //定时任务 services.AddHostedService(); diff --git a/common/Tnb.Common/Extension/EnumerableExtensions.cs b/common/Tnb.Common/Extension/EnumerableExtensions.cs index 0c7d30ae..a1922799 100644 --- a/common/Tnb.Common/Extension/EnumerableExtensions.cs +++ b/common/Tnb.Common/Extension/EnumerableExtensions.cs @@ -70,4 +70,21 @@ public static class EnumerableExtensions collection = collection as IList ?? collection.ToList(); return !collection.Any(); } + /// + /// Contains扩展 + /// added by ly on 20230814 + /// + /// + /// + /// + /// + public static bool In(this T obj, IEnumerable collection) + { + var result = false; + foreach (var item in collection) + { + result |= item.Equals(obj); + } + return result; + } } \ No newline at end of file diff --git a/system/Tnb.OAuth/OAuthService.cs b/system/Tnb.OAuth/OAuthService.cs index 9c389e8f..a701c81b 100644 --- a/system/Tnb.OAuth/OAuthService.cs +++ b/system/Tnb.OAuth/OAuthService.cs @@ -142,7 +142,7 @@ public class OAuthService : IDynamicApiController, ITransient private readonly IMHandler _imHandler; - + /// /// 初始化一个类型的新实例. @@ -607,8 +607,7 @@ public class OAuthService : IDynamicApiController, ITransient }, tokenTimeout); //modify by ly on 20230804 - UserManager.AsscessToken = accessToken; - await _cacheManager.SetAsync("AsscessToken", accessToken,TimeSpan.FromMinutes(30)); + await _cacheManager.SetAsync("AsscessToken", accessToken, TimeSpan.FromMinutes(-1)); // 单点登录标识缓存 if (_oauthOptions.Enabled) _cacheManager.Set("OnlineTicket_" + input.online_ticket, options.ConfigId);