/// <summary> /// Starts the engine and updates the Cache from Database /// </summary> /// <returns>Returns task to wait for until Startup has completed (true) or failed (false)</returns> public static async Task <bool> StartupAsync(IConfigurationRoot configuration) { await lockStartup.WaitAsync(); var engineConfig = configuration.GetSection("Engine"); logger.Info("<<<<<<<<<<<<<<<<<<<< CarrierLink >>>>>>>>>>>>>>>>>>>>"); logger.Info("Startup..."); if (IsRunning()) { logger.Error("Engine is already running"); return(false); } Pool.Initialize(() => new PgSQL(configuration.GetConnectionString("CarrierLink"))); // Message Buffer Setup if (!int.TryParse(engineConfig.GetValue <string>("Workers"), out int workers) || workers < 1) { throw new InvalidOperationException("Workers needs to be a positive number"); } // WaitingTimeWarningThreshold if (!int.TryParse(engineConfig.GetValue <string>("WaitingTimeWarningThreshold"), out waitingTimeWarningThreshold) || waitingTimeWarningThreshold < 1 || waitingTimeWarningThreshold > 10) { logger.Warn(@"Configuration Parameter ""WaitingTimeWarningThreshold"" is not an Integer or not between 1 and 10, setting value to 2 (default)"); waitingTimeWarningThreshold = 2; } waitingTimeWarningThreshold *= 1000; // YateMaximumWaitingTime if (!int.TryParse(engineConfig.GetValue <string>("YateMaximumWaitingTime"), out yateMaximumWaitingTime) || yateMaximumWaitingTime < 1 || yateMaximumWaitingTime > 300) { logger.Warn(@"Configuration Parameter ""YateMaximumWaitingTime"" is not an Integer or not between 1 and 300, setting value to 10 (default)"); yateMaximumWaitingTime = 2; } yateMaximumWaitingTime *= 1000; messageBuffer = new ActionBlock <Message>(async message => await _ProcessMessage(message), new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = workers, CancellationToken = CancellationToken, SingleProducerConstrained = false } ); // Delete old registrations var database = Pool.Database.Get(); try { Id = await database.ControllerStartup(engineConfig.GetValue <string>("ControlServerName"), CancellationToken); } catch { logger.Error($"Controller Name '{engineConfig.GetValue<string>("ControlServerName")}' is not registered in database. ABORTING."); throw new ArgumentException($"Controller Name '{engineConfig.GetValue<string>("ControlServerName")}' is not registered in database."); } await database.ControllerLog(Id, "Startup Initiated", CancellationToken); // Default Value State = EngineState.Stopped; Cache.Initialize(); await database.ControllerLog(Id, "Updating Cache", CancellationToken); await Cache.Update(false); // Connection Management Timer connectionManagmentTimer = new System.Timers.Timer { AutoReset = true, Interval = 2000 }; connectionManagmentTimer.Elapsed += _ConnectionManagmentTimer_Elapsed; State = EngineState.Running; await database.ControllerLog(Id, "Startup Completed", CancellationToken); Pool.Database.Put(database); // Start Timers connectionManagmentTimer.Start(); AutomaticJobsManager.Start(); logger.Info("Startup completed"); lockStartup.Release(); return(true); }
/// <summary> /// Removes the handlers and stops the engine /// </summary> /// <returns>Returns task to wait for until shutdown has completed</returns> public static async Task ShutdownAsync() { await lockShutdown.WaitAsync(); logger.Info("Shutdown..."); if (!IsRunning()) { lockShutdown.Release(); return; } var db = Pool.Database.Get(); await db.ControllerLog(Id, "Shutdown Initiated", CancellationToken); State = EngineState.Stopping; // Stop jobs AutomaticJobsManager.Stop(); // Disconnect connections connectionManagmentTimer.Stop(); var connectionsToStop = new List <Task>(); var registeredConnections = nodeConnections.Select(nc => nc.Value).ToList(); foreach (var node in registeredConnections) { if (node.IsConnected) { connectionsToStop.Add(_Disconnect(node.Id)); } } await Task.WhenAll(connectionsToStop); connectionsToStop = null; // Signal completition of message processing and wait for buffer to complete, max. 5 seconds messageBuffer.Complete(); int timeout = 0; while (messageBuffer.InputCount > 0 && timeout < 20) { await Task.Delay(250); timeout++; } // Cancel parallel operations in Main logger.Debug("Cancelling processes, may take up to two minutes."); cancellationToken.Cancel(); /// Wait 10 seconds await Task.Delay(10000); var databaseCancellationTokenSource = new CancellationTokenSource(); databaseCancellationTokenSource.CancelAfter(30000); await db.ControllerLog(Id, "Remaining Connections terminated", databaseCancellationTokenSource.Token); await db.ControllerLog(Id, "Shutdown Completed", databaseCancellationTokenSource.Token); await db.ControllerShutdown(Id, databaseCancellationTokenSource.Token); Pool.Database.Put(db); databaseCancellationTokenSource.Dispose(); databaseCancellationTokenSource = null; // Shutdown the Cache Cache.Shutdown(); State = EngineState.Stopped; logger.Info("Shutdown completed"); messageBuffer = null; cancellationToken.Dispose(); cancellationToken = null; connectionManagmentTimer.Dispose(); connectionManagmentTimer = null; lockShutdown.Release(); lockShutdown.Dispose(); lockShutdown = null; logger = null; }