using HH.WCS.HangYang.api; using HH.WCS.HangYang.core; using HH.WCS.HangYang.device; using HH.WCS.HangYang.process; using HH.WCS.HangYang.util; using HH.WCS.HangYang.wms; using Microsoft.Owin.Hosting; using NLog; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using Topshelf; using Monitor = HH.WCS.HangYang.core.Monitor; namespace HH.WCS.HangYang { internal class Program { static void Main(string[] args) { Settings.Init(); //1.0 开启api Startup(); //2.0 开启tcp StartTcp(); //3.0 开启线程 var rc = HostFactory.Run(x => { using (var worker = new WorkThread()) { worker.Start(); // 主线程等待退出信号 Console.CancelKeyPress += (s, e) => worker.Stop(); Thread.Sleep(Timeout.Infinite); } x.RunAsLocalSystem(); x.SetDescription("hh123"); x.SetDisplayName("hh123.wms"); x.SetServiceName("hh123.wms"); }); var exitCode = (int)Convert.ChangeType(rc, rc.GetTypeCode()); Environment.ExitCode = exitCode; } private static void Startup() { Console.WriteLine("Startup ApiController"); Task.Run(() => { //var url = "http://192.168.1.87:8901";//{SettingHelper.port} var url = $"http://+:{Settings.port}";// Console.WriteLine(url); using (WebApp.Start(url)) { Console.WriteLine("Running on {0}", url); Console.ReadLine(); } }); } private static void StartTcp() { //new TcpServer("192.168.1.87"); var host = Dns.GetHostEntry(Dns.GetHostName()); foreach (var ip in host.AddressList) { if (ip.AddressFamily == AddressFamily.InterNetwork) { Console.WriteLine($"ip= {ip.ToString()}"); new TcpServer(ip.ToString()); } } } public class WorkThread : IDisposable { private readonly List _tasks = new List(); private readonly CancellationTokenSource _cts = new CancellationTokenSource(); private bool _disposed; private readonly Dictionary _taskRegistry = new Dictionary { {"循环作业创建任务", WCSCore.ExecuteJob}, {"循环入库暂存区生成入库任务", WCSCore.ProcessZoneInventoryCycle}, {"根据配盘单生成出库任务", WCSCore.GenerateFromPicking}, }; private readonly List<(string Name, Action Action, Task Task)> _taskInfoList = new List<(string, Action, Task)>(); public void Start() { // 创建所有任务 foreach (var task in _taskRegistry) { var managedTask = CreateManagedTask(task.Value, task.Key, _cts.Token); _taskInfoList.Add((task.Key, task.Value, managedTask)); _tasks.Add(managedTask); } // 启动健康监控 _tasks.Add(StartHealthMonitor()); LogHelper.Info($"工作线程已启动,共 {_tasks.Count} 个任务"); } public void Stop() { if (_cts.IsCancellationRequested) return; LogHelper.Info("正在停止工作线程..."); _cts.Cancel(); Task.WhenAll(_tasks) .ContinueWith(t => { _tasks.Clear(); LogHelper.Info("所有工作线程已停止"); }); } private Task CreateManagedTask(Action action, string taskName, CancellationToken ct) { int retryCount = 0; return Task.Run(async () => { LogHelper.Info($"任务 [{taskName}] 启动"); while (!ct.IsCancellationRequested) { try { var stopwatch = Stopwatch.StartNew(); action(); stopwatch.Stop(); if (stopwatch.ElapsedMilliseconds > 10000) { LogHelper.Info($"任务 [{taskName}] 执行时间过长: {stopwatch.ElapsedMilliseconds}ms"); } } catch (OperationCanceledException) { LogHelper.Info($"任务 [{taskName}] 已取消"); break; } catch (Exception ex) { LogHelper.Error($"任务 [{taskName}] 执行失败: {ex.Message}", ex); var delay = Math.Min(30000, 1000 * (int)Math.Pow(2, retryCount)); await Task.Delay(delay, ct); retryCount++; } await Task.Delay(3000, ct); } LogHelper.Info($"任务 [{taskName}] 已退出"); }, ct); } public void Dispose() { if (_disposed) return; Stop(); _cts.Dispose(); _disposed = true; GC.SuppressFinalize(this); } private Task StartHealthMonitor() { return Task.Run(async () => { while (!_cts.IsCancellationRequested) { var faultedTasks = _taskInfoList.Where(x => x.Task.IsFaulted).ToList(); foreach (var (name, action, task) in faultedTasks) { LogHelper.Info($"检测到失败任务: {name}"); // 移除旧任务 _taskInfoList.Remove((name, action, task)); _tasks.Remove(task); // 创建新任务 var newTask = CreateManagedTask(action, name, _cts.Token); _taskInfoList.Add((name, action, newTask)); _tasks.Add(newTask); } await Task.Delay(10000, _cts.Token); } }, _cts.Token); } } } }