private async Task ShutdownModule(ModuleState module) { State s = module.State; if (s == State.ShutdownStarted || s == State.ShutdownCompleted) { return; } module.State = State.ShutdownStarted; logger.Info($"Starting shutdown of module {module.Name}..."); try { if (module.RunTask != null) { await module.RunTask; } if (s == State.InitComplete || s == State.InitError) { await module.Instance.InitAbort(); } await module.FlushVariables(); logger.Info($"Shutdown of module {module.Name} completed."); } catch (Exception exp) { string msg = $"Shutdown exception in module '{module.Name}': " + exp.Message; Log_Exception(Severity.Warning, exp, "ModuleShutdownError", msg, module.ID); } module.State = State.ShutdownCompleted; module.SetInstanceNull(); }
private void StartRunningModule(ModuleState module) { module.State = State.Running; Func <bool> fShutdown = () => { return(module.State == State.ShutdownStarted); }; Task runTask = module.Instance .Run(fShutdown) .ContinueOnMainThread((task) => { if (module.State == State.Running) { string restartReason = ""; if (task.IsFaulted) { string msg = $"Module '{module.Name}' threw exception in Run: " + task.Exception !.GetBaseException().Message; Log_Exception(Severity.Warning, task.Exception, "ModuleRunError", msg, module.ID); restartReason = "Exception in Run"; } else { restartReason = "Early return from Run"; } Task.Delay(1000).ContinueOnMainThread((tt) => { Task ignored = RestartModule(module, restartReason); }); } }); module.RunTask = runTask; }
internal void Notify_AlarmOrEvent(ModuleState module, AlarmOrEventInfo e) { var ae = new AlarmOrEvent() { ModuleID = module.ID, ModuleName = module.Name, Time = e.Time, IsSystem = false, Severity = e.Severity, Type = e.Type, Message = e.Message, Details = e.Details, AffectedObjects = e.AffectedObjects, Initiator = e.Initiator }; reqHandler.OnAlarmOrEvent(ae); string msg = e.Message; switch (e.Severity) { case Severity.Info: module.logger.Info(msg); break; case Severity.Warning: module.logger.Warn(msg); break; case Severity.Alarm: module.logger.Error(msg); break; } }
internal async Task RestartModule(ModuleState module, string reason, int tryCounter = 0) { Log_Warn("ModuleRestart", $"Restarting module '{module.Name}'. Reason: {reason}", module.ID); const int TimeoutSeconds = 10; try { Task tShutdown = ShutdownModule(module); Task t = await Task.WhenAny(tShutdown, Task.Delay(TimeSpan.FromSeconds(TimeoutSeconds))); if (t != tShutdown) { string msg = $"Shutdown request for module '{module.Name}' failed to complete within {TimeoutSeconds} seconds."; Log_Warn("ShutdownTimeout", msg, module.ID); // go ahead and hope for the best... } if (shutdown) { return; } module.CreateInstance(); await InitModule(module); StartRunningModule(module); } catch (Exception exp) { Log_Exception(Severity.Alarm, exp, "ModuleRestartError", $"Restart of module '{module.Name}' failed: {exp.Message}", module.ID); int delayMS = Math.Min(10 * 1000, (tryCounter + 1) * 1000); await Task.Delay(delayMS); Task ignored = RestartModule(module, reason, tryCounter + 1); } }
internal void Notify_VariableValuesChanged(ModuleState module, List <VariableValue> values) { if (logger.IsDebugEnabled) { logger.Debug("VariableValuesChanged:\n\t" + string.Join("\n\t", values.Select(x => x.ToString()))); } module.UpdateVariableValues(values); }
private Variable?GetVariableDescription(VariableRef varRef) { string moduleID = varRef.Object.ModuleID; ModuleState module = modules.FirstOrDefault(m => m.ID == moduleID); if (module == null) { return(null); } return(module.GetVarDescription(varRef)); }
private async Task InitModule(ModuleState module) { Module info = module.Config; try { logger.Info($"Starting module {module.Name}..."); VariableValue[] restoreVariableValues = module.GetVariableValues(); var configItems = info.Config.ToList(); if (!string.IsNullOrEmpty(info.ExternalCommand)) { configItems.Add(new NamedValue("ExternalCommand", info.ExternalCommand)); } if (!string.IsNullOrEmpty(info.ExternalArgs)) { configItems.Add(new NamedValue("ExternalArgs", info.ExternalArgs)); } var initInfo = new ModuleInitInfo() { ModuleID = module.ID, ModuleName = module.Name, LoginPassword = module.Password, LoginServer = "localhost", LoginPort = listenPort, DataFolder = GetDataFolder(module.Config), Configuration = configItems.ToArray(), InProcApi = reqHandler, }; await module.Instance.Init(initInfo, restoreVariableValues, module, null); ObjectInfo[] allObjs = await module.Instance.GetAllObjects(); module.SetAllObjects(allObjs); module.State = State.InitComplete; logger.Info($"Init of module {module.Name} completed."); } catch (Exception exp) { module.State = State.InitError; module.LastError = exp.Message; throw new Exception($"Startup of module {info.Name} failed: " + exp.Message, exp); } }
internal void Notify_ConfigChanged(ModuleState module, List <ObjectRef> changedObjects) { try { Task <ObjectInfo[]> task = module.Instance.GetAllObjects(); task.ContinueOnMainThread(t => { if (t.IsFaulted) { var ignored = RestartModule(module, "GetAllObjects() failed in Notify_ConfigChanged: " + t.Exception?.Message); } else { ObjectInfo[] allObjs = t.Result; module.SetAllObjects(allObjs); } }); } catch (Exception exp) { var ignored = RestartModule(module, "GetAllObjects() failed in Notify_ConfigChanged: " + exp.Message); } reqHandler.OnConfigChanged(changedObjects, module.GetObjectParent); }
internal void Notify_AlarmOrEvent(ModuleState module, AlarmOrEventInfo e) { Origin?initiator = e.Initiator; if (initiator.HasValue) { Origin origin = initiator.Value; string id = origin.ID; if (origin.Type == OriginType.User) { User user = userManagement.Users.FirstOrDefault(u => u.ID == id); if (user != null) { origin.Name = user.Name; } else if (origin.Name == null) { origin.Name = ""; } } else if (origin.Type == OriginType.Module) { var theModule = modules.FirstOrDefault(m => m.ID == id); if (theModule != null) { origin.Name = theModule.Name; } else if (origin.Name == null) { origin.Name = ""; } } initiator = origin; } var ae = new AlarmOrEvent() { ModuleID = module.ID, ModuleName = module.Name, Time = e.Time, IsSystem = false, Severity = e.Severity, ReturnToNormal = e.ReturnToNormal, Type = e.Type, Message = e.Message, Details = e.Details, AffectedObjects = e.AffectedObjects, Initiator = initiator }; reqHandler.OnAlarmOrEvent(ae); bool logInfo = module.UpdateWarningAlarmState(e); string msg = e.Message; switch (e.Severity) { case Severity.Info: if (logInfo) { module.logger.Info(msg); } break; case Severity.Warning: module.logger.Warn(msg); break; case Severity.Alarm: module.logger.Error(msg); break; } }