/// <summary> /// 启动,软停止和硬停止都可用 /// </summary> public void Start() { if (!isRunning) { isRunning = true; tcpServer.Start(); //每两秒扫描一次命令缓冲区 ScanActionTimer = YUtil.SetInterval(2000, () => { using (ActionLock.Lock()) { //自动执行任务 var canClear = true; foreach (var pair in ActionCache) { if (pair.Value != SmAction.NoAction && ActionClientDict.ContainsKey(pair.Key)) { try { var state = ActionClientDict[pair.Key]; tcpServer.Send(state, SmParamApi.BuildAlarmPackage(state.ModuleAddr, pair.Value)); Logger.Debug($"发送命令 {Enum.GetName(typeof(SmAction), pair.Value)} 成功 {pair.Key}"); ActionCache[pair.Key] = SmAction.NoAction; } catch { canClear = false; Logger.Error($"发送命令 {Enum.GetName(typeof(SmAction), pair.Value)} 异常 {pair.Key}", 24 * 3600); } } } if (canClear) { YUtil.ClearTimeout(ScanActionTimer); } } }); } }
/// <summary> /// 程序将在 totalSec 之后重启 /// </summary> /// <param name="totalSec"></param> /// <param name="percent"></param> /// <param name="message"></param> void restartAppAfterSec(int totalSec, double percent, string message = "程序启动超时") { try { var latestLog = getAppLatestStartupLog(); //连续启动失败次数越多,等待启动时间越长 if (latestLog?.ContinueFailedTimes > 0 && !HmiConfig.IsDevUserEnv) { totalSec = latestLog.ContinueFailedTimes * 10; } updateAppStartupLog(message); } catch (Exception e) { Logger.Error("启动日志出问题", e); } //显示重启提示 var waitMessage = $"{message},将在 {totalSec} 秒后尝试重启"; updateLoadingMessage(waitMessage, percent, 0); YUtil.SetInterval(1000, t => { var wait = totalSec - t; waitMessage = $"{message},将在 {wait} 秒后尝试重启"; updateLoadingMessage(waitMessage, percent, 0); if (wait <= 0) { App.Restart(); } }, totalSec); }
/// <summary> /// 配置文件加载之后才能对其初始化 /// 1. 每隔指定时间(15分钟)关闭显示器 /// 2. 每天8:00打开显示器 /// 3. 定时上传Cpm到Mq /// </summary> public async Task Init() { JobManager.JobException += info => Logger.Error("An error just happened with a scheduled job: " + info.Exception); //自动关闭显示器 await App.Store.Dispatch(sysEffects.StartCloseScreenTimer(new SysActions.StartCloseScreenTimer(HmiConfig.CloseScreenInterval))); //启动定时上传Cpms到Mq定时器 await App.Store.Dispatch(mqEffects.StartUploadCpmsInterval(new MqActions.StartUploadCpmsInterval(HmiConfig.QueUpdateWebBoard, HmiConfig.UploadWebBoardInterval))); //定义完成一些额外的任务 //YUtil.SetInterval(HmiConfig.UploadWebBoardInterval, () => { // updateGrafana(); //}); //一小时缓存一次485状态 YUtil.SetInterval(3600000, () => { persistCom485State(); }); //每天8点打开显示器 Schedule(() => { App.Store.Dispatch(new SysActions.OpenScreen()); App.Logger.Info("8 点开启显示器"); }).ToRunEvery(1).Days().At(8, 0); JobManager.Initialize(this); }
/// <summary> /// 初始化 /// </summary> public void Init() { eventHandlers = new Dictionary <Type, EventHandler <YEventArgs> >(); eventHandlers[typeof(PipeReceived)] = whenPipeReceived; App.EventStore.Subscribe(eventHandlers); //HmiPro 软件保活 YUtil.SetInterval(60000, keepHmiAlive); Logger = LoggerHelper.Create(GetType().ToString()); }
void initStartUploadCpmsIntervalEffect() { StartUploadCpmsInterval = App.Store.asyncActionVoid <MqActions.StartUploadCpmsInterval>(async(dipatch, getState, instance) => { dipatch(instance); await Task.Run(() => { YUtil.SetInterval(instance.Interval, () => { App.Store.Dispatch(UploadCpms(new MqActions.UploadCpms(getState().CpmState.OnlineCpmsDict, instance.QueueName))); }); }); }); }
/// <summary> /// 初始化上面的 Effect /// </summary> /// <param name="sysService"></param> public SysEffects(SysService sysService) { UnityIocService.AssertIsFirstInject(GetType()); Logger = LoggerHelper.CreateLogger(GetType().ToString()); //启动http解析服务 StartHttpSystem = App.Store.asyncAction <SysActions.StartHttpSystem, bool>( async(dispatch, getState, instance) => { dispatch(instance); var isStarted = await sysService.StartHttpSystem(instance); if (isStarted) { App.Store.Dispatch(new SysActions.StartHttpSystemSuccess()); } else { App.Store.Dispatch(new SysActions.StartHttpSystemFailed()); } return(isStarted); }); //启动关闭显示器定时器 StartCloseScreenTimer = App.Store.asyncActionVoid <SysActions.StartCloseScreenTimer>( async(dispatch, getState, instance) => { dispatch(instance); await Task.Run(() => { if (CloseScrrenTimer != null) { YUtil.RecoveryTimeout(CloseScrrenTimer); } else { CloseScrrenTimer = YUtil.SetInterval(instance.Interval, () => { App.Store.Dispatch(new SysActions.CloseScreen()); }); } }); }); //停止关闭显示器定时器 StopCloseScrenTimer = App.Store.asyncActionVoid <SysActions.StopCloseScreenTimer>( async(dispatch, getState, instance) => { dispatch(instance); await Task.Run(() => { if (CloseScrrenTimer != null) { YUtil.ClearTimeout(CloseScrrenTimer); } }); }); }
/// <summary> /// 异步启动服务,将在线参数字典与AppState全局字典进行绑定 /// </summary> /// <param name="ip"></param> /// <param name="port"></param> /// <returns></returns> public Task StartAsync(string ip, int port) { return(Task.Run(() => { if (SmParamTcp == null) { SmParamTcp = new YSmParamTcp(ip, port, LoggerHelper.CreateLogger("YSmParamTcp")); SmParamTcp.OnDataReceivedAction += whenSmActived; OnlineCpmDict = App.Store.GetState().CpmState.OnlineCpmsDict; //检查超时 YUtil.SetInterval(HmiConfig.CpmTimeout, () => { checkCpmTimeout(HmiConfig.CpmTimeout); }); } SmParamTcp.Start(); })); }
/// <summary> /// 程序将在 totalSec 秒后自动关闭 /// </summary> void shutdownAppAfterSec(int totalSec, double percent, string message = "程序启动超时") { try { updateAppStartupLog(message); } catch { } YUtil.SetInterval(1000, t => { var wait = totalSec - t; var waitMessage = $"{message},将在 {wait} 秒后关闭"; updateLoadingMessage(waitMessage, percent, 0); if (wait <= 0) { App.Shutdown(); } }, totalSec); }
/// <summary> /// 周期的去ping模块的ip,更新其离线状态 /// </summary> /// <param name="state"></param> /// <param name="intervalSec"></param> private static void updateCom485Interval(State state, int intervalSec) { void update() { foreach (var pair in state.Com485StatusDict) { Ping ping = new Ping(); var ret = ping.Send(pair.Key, 2000); if (ret?.Status != IPStatus.Success) { pair.Value.Status = SmSingleStatus.Offline; pair.Value.Time = DateTime.Now; } } } Task.Run(() => { update(); YUtil.SetInterval(intervalSec * 1000, update); }); }
/// <summary> /// 配置文件加载成功之后执行的一些初始化 /// </summary> async void afterConfigLoaded() { //== 初始化部分State updateLoadingMessage("正在初始化系统核心...", 0.5); App.Store.Dispatch(new ViewStoreActions.Init()); App.Store.Dispatch(new CpmActions.Init()); App.Store.Dispatch(new AlarmActions.Init()); App.Store.Dispatch(new OeeActions.Init()); App.Store.Dispatch(new DMesActions.Init()); App.Store.Dispatch(new DpmActions.Init()); var sysEffects = UnityIocService.ResolveDepend <SysEffects>(); var cpmEffects = UnityIocService.ResolveDepend <CpmEffects>(); var mqEffects = UnityIocService.ResolveDepend <MqEffects>(); updateLoadingMessage("正在连接服务器...", 0.55); var task = Task.Run(() => { mqEffects.Start(); }); //更新连接服务器的进度 double p = 0.55; bool isMqEffectsStarted = false; Timer updateTimer = null; updateTimer = YUtil.SetInterval(500, () => { if (!isMqEffectsStarted) { p += 0.01; updateLoadingMessage("正在连接服务器...", p, 0); Logger.Debug("正在连接服务器..." + p.ToString("P1")); } if (isMqEffectsStarted || p > 0.64) { YUtil.ClearTimeout(updateTimer); } }); isMqEffectsStarted = Task.WaitAll(new[] { task }, 10000); YUtil.ClearTimeout(updateTimer); if (!isMqEffectsStarted) { updateLoadingMessage("连接 Mq 超时...", 0.6); App.Store.Dispatch(new SysActions.AddMarqueeMessage(SysActions.MARQUEE_CONECT_MQ_TIMEOUT, "Mq 连接超时")); restartAppAfterSec(10, 0.6, "连接 Mq 超时"); return; } updateLoadingMessage("正在注册程序...", 0.65); if (!await YUtil.CheckHttpFileExist(HmiConfig.StaticServerUrl + "/verify.txt")) { updateLoadingMessage("程序启动失败,请联系管理员", 0.66); restartAppAfterSec(10, 0.66, "程序启动失败,请联系管理员"); return; } UnityIocService.ResolveDepend <DMesCore>().Init(); UnityIocService.ResolveDepend <AlarmCore>().Init(); UnityIocService.ResolveDepend <CpmCore>().Init(); UnityIocService.ResolveDepend <OeeCore>().Init(); UnityIocService.ResolveDepend <DpmCore>().Init(); UnityIocService.ResolveDepend <HookCore>().Init(); //Http 命令解析 updateLoadingMessage("正在启动Http服务...", 0.7); var starHttpSystem = App.Store.Dispatch(sysEffects.StartHttpSystem(new SysActions.StartHttpSystem($"http://+:{HmiConfig.CmdHttpPort}/"))); //参数采集服务 updateLoadingMessage("正在启动参数采集服务...", 0.75); var startCpmServer = App.Store.Dispatch(cpmEffects.StartServer(new CpmActions.StartServer(HmiConfig.CpmTcpIp, HmiConfig.CpmTcpPort))); //监听排产和来料 updateLoadingMessage("正在启动监听排产服务...", 0.8); Dictionary <string, Task <bool> > startListenMqDict = new Dictionary <string, Task <bool> >(); foreach (var pair in MachineConfig.MachineDict) { //监听排产任务 var stQueueName = @"QUEUE_" + pair.Key; var stTask = App.Store.Dispatch(mqEffects.StartListenSchTask(new MqActions.StartListenSchTask(pair.Key, stQueueName))); startListenMqDict[stQueueName] = stTask; //监听来料 var smQueueName = $@"JUDGE_MATER_{pair.Key}"; var smTask = App.Store.Dispatch(mqEffects.StartListenScanMaterial(new MqActions.StartListenScanMaterial(pair.Key, smQueueName))); startListenMqDict[smQueueName] = smTask; } //监听人员打卡 updateLoadingMessage("正在启动监听人员打卡...", 0.85); var empRfidTask = App.Store.Dispatch(mqEffects.StartListenEmpRfid(new MqActions.StartListenEmpRfid(MachineConfig.HmiName + "_employee", HmiConfig.TopicEmpRfid))); startListenMqDict["rfidEmpTask"] = empRfidTask; //监听轴号卡 updateLoadingMessage("正在启动监听盘卡扫描...", 0.90); var axisRfidTask = App.Store.Dispatch(mqEffects.StartListenAxisRfid(new MqActions.StartListenAxisRfid(MachineConfig.HmiName + "_axis", HmiConfig.TopicListenHandSet))); startListenMqDict["rfidAxisTask"] = axisRfidTask; //监听机台命令 updateLoadingMessage("正在启动监听机台命令...", 0.92); var cmdTask = App.Store.Dispatch(mqEffects.StartListenCmd(new MqActions.StartListenCmd(MachineConfig.HmiName + "_cmd", HmiConfig.TopicCmdReceived))); startListenMqDict["cmdTask"] = cmdTask; updateLoadingMessage("正在启动系统核心服务...", 0.95); var tasks = new List <Task <bool> >() { starHttpSystem, startCpmServer }; tasks.AddRange(startListenMqDict.Values); //检查各项任务启动情况 await Task.Run(() => { //等等所有任务完成 var isStartedOk = Task.WaitAll(tasks.ToArray(), 30000); if (!isStartedOk) { var message = "系统核心启动超时,请检查网络连接"; updateLoadingMessage(message, 0.95); restartAppAfterSec(10, 0.95, "系统核心启动超时"); return; } //是否启动完成Cpm服务 var isCpmServer = startCpmServer.Result; if (!isCpmServer) { var message = "参数采集核心启动失败"; updateLoadingMessage(message, 0.95, 0); restartAppAfterSec(10, 0.95, message); return; } //是否启动完成Http解析系统 var isHttpSystem = starHttpSystem.Result; if (!isHttpSystem) { var message = "Http 核心启动失败"; updateLoadingMessage(message, 0.95, 0); restartAppAfterSec(10, 0.95, message); return; } //是否完成监听Mq foreach (var pair in startListenMqDict) { var isStartListenMq = pair.Value.Result; var mqKey = pair.Key.ToUpper(); if (!isStartListenMq) { string failedMessage = string.Empty; if (mqKey.Contains("QUEUE")) { failedMessage = $"监听Mq 排产队列 {pair.Key} 失败"; } else if (mqKey.Contains("JUDGE_MATER")) { failedMessage = $"监听Mq 扫描来料队列 {pair.Key} 失败"; } else if (mqKey.Contains("RFIDEMP")) { failedMessage = $"监听mq 人员打卡 数据失败"; } else if (mqKey.Contains("RFIDAXIS")) { failedMessage = $"监听Mq 线盘卡失败"; } else if (mqKey.Contains("CMD")) { failedMessage = $"监听Mq 机台命令失败"; } if (!string.IsNullOrEmpty(failedMessage)) { updateLoadingMessage(failedMessage, 0.95, 0); restartAppAfterSec(10, 0.95, failedMessage); return; } } } if (HmiConfig.IsDevUserEnv) { updateLoadingMessage("系统核心启动完毕,正在渲染界面...", 1, 0); App.Store.Dispatch(new SysActions.AppInitCompleted()); return; } var percent = 0.95; YUtil.SetInterval(300, t => { percent += 0.01; updateLoadingMessage("系统核心启动完毕,正在渲染界面...", percent, 0); if (t == 5 || percent >= 1) { App.Store.Dispatch(new SysActions.AppInitCompleted()); } }, 5); }); //update: 2018-3-28 // 将调度器最后启用,这些调度器需要依赖比较多,但本身不提供依赖 updateLoadingMessage("正在启动调度器...", 0.98); await UnityIocService.ResolveDepend <SchCore>().Init(); }