Server.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.IO.Abstractions;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Net.Sockets;
  8. using BO.ProcessServer.Business.StatisticCounters;
  9. using BO.ProcessServer.Business.Workers;
  10. using BO.ProcessServer.Business.Workers.Contexts;
  11. using BO.ProcessServer.Options;
  12. using Connector.PS;
  13. using Quadarax.Foundation.Core.IO;
  14. using Quadarax.Foundation.Core.Logging;
  15. using Quadarax.Foundation.Core.Object;
  16. namespace BO.ProcessServer.Business
  17. {
  18. internal class Server : DisposableObject
  19. {
  20. #region *** Private fields ***
  21. private Configuration _configuration;
  22. private IFileSystem _fileSystem;
  23. private IList<ServerProcess> _processes;
  24. protected ILog Log { get; }
  25. protected ILog LogLifecycle { get; }
  26. protected Statistics Statistics { get; }
  27. private Pool _pool;
  28. private PullDocumentsWorker _wkPull;
  29. private RetentionWorker _wkRetention;
  30. private ProcessingDocumentsWorker _wkProcessing;
  31. private IConnectionPS _connection;
  32. #endregion
  33. #region *** Public properties ***
  34. public bool IsRunning { get; private set; }
  35. #endregion
  36. #region *** Constructors ***
  37. public Server(Configuration serverConfiguration, IFileSystem fileSystem, ILogger logger)
  38. {
  39. _configuration = serverConfiguration ?? throw new ArgumentNullException(nameof(serverConfiguration));
  40. _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
  41. if (logger == null)
  42. throw new ArgumentNullException(nameof(logger));
  43. Log = logger.GetLogger(typeof(Server));
  44. LogLifecycle = logger.GetLogger("Lifecycle");
  45. Statistics = new Statistics();
  46. ValidateConfiguration();
  47. _processes = new List<ServerProcess>();
  48. _connection = new Connector(_configuration, _fileSystem);
  49. _pool = new Pool(_configuration, _fileSystem, logger);
  50. _wkPull = new PullDocumentsWorker(_connection, _configuration.System.PoolPullInterval, _fileSystem, Statistics, _pool, logger);
  51. _wkRetention = new RetentionWorker(new CfgCtx(_configuration, Statistics, _pool));
  52. _wkProcessing = new ProcessingDocumentsWorker(_configuration, _processes, _connection, _fileSystem, Statistics, _pool, logger);
  53. }
  54. #endregion
  55. #region *** Public operations ***
  56. public void Start()
  57. {
  58. if (IsRunning)
  59. {
  60. LogWarn($"Instance '{_configuration.System.Identification}' already running. Start skipped.");
  61. return;
  62. }
  63. LogDebug($"Starting instance '{_configuration.System.Identification}' ...");
  64. _wkPull.Start();
  65. _wkRetention.Start();
  66. _wkProcessing.Start();
  67. Statistics.GetCounter<TimespanCounter>(Statistics.CNT_PS_ONLINE_DUR).Start();
  68. IsRunning = true;
  69. LogInfo( $"Instance '{_configuration.System.Identification}' STARTED.");
  70. LogLifecycle.Log(LogSeverityEnum.Info, $"Instance '{_configuration.System.Identification}' STARTED.");
  71. }
  72. public void Stop()
  73. {
  74. if (!IsRunning)
  75. {
  76. LogWarn($"Instance '{_configuration.System.Identification}' already stopped. Stop skipped.");
  77. return;
  78. }
  79. LogDebug($"Stopping instance '{_configuration.System.Identification}' ...");
  80. StopAll();
  81. Statistics.GetCounter<TimespanCounter>(Statistics.CNT_PS_ONLINE_DUR).Stop();
  82. IsRunning = false;
  83. LogInfo( $"Instance '{_configuration.System.Identification}' STOPPED.");
  84. LogLifecycle.Log(LogSeverityEnum.Info, $"Instance '{_configuration.System.Identification}' STOPPED.");
  85. LogLifecycle.Log(LogSeverityEnum.Info, Statistics.ToString());
  86. }
  87. #endregion
  88. #region *** Overrides ***
  89. protected override void OnDisposing()
  90. {
  91. if (IsRunning)
  92. StopAll(true);
  93. _wkPull?.Dispose();
  94. _wkRetention?.Dispose();
  95. _wkProcessing?.Dispose();
  96. _connection?.Dispose();
  97. _pool?.Dispose();
  98. LogDebug($"Instance '{_configuration.System.Identification}' disposed.");
  99. _configuration = null;
  100. _fileSystem = null;
  101. _wkPull=null;
  102. _wkRetention=null;
  103. _wkProcessing = null;
  104. _connection=null;
  105. _pool = null;
  106. }
  107. #endregion
  108. #region *** Private Operations ***
  109. public void LogDebug(string message)
  110. {
  111. LogRaw(LogSeverityEnum.Debug, message);
  112. }
  113. public void LogInfo(string message)
  114. {
  115. LogRaw(LogSeverityEnum.Info, message);
  116. }
  117. public void LogWarn(string message)
  118. {
  119. LogRaw(LogSeverityEnum.Warn, message);
  120. }
  121. public void LogRaw(LogSeverityEnum severity, string message)
  122. {
  123. Log.Log(severity, message);
  124. }
  125. private void ValidateConfiguration()
  126. {
  127. if (string.IsNullOrEmpty(_configuration.System.Identification))
  128. throw new ArgumentNullException(nameof(_configuration.System.Identification),
  129. "Mandatory process server identification.");
  130. if (string.IsNullOrEmpty(_configuration.System.PreferredInterface))
  131. _configuration.System.PreferredInterface = "auto";
  132. var host = Dns.GetHostEntry(Dns.GetHostName());
  133. if (_configuration.System.PreferredInterface.Trim().ToLower() == "auto")
  134. {
  135. _configuration.System.PreferredInterface = host.AddressList.Where(x =>
  136. x.AddressFamily == AddressFamily.InterNetwork ||
  137. x.AddressFamily == AddressFamily.InterNetworkV6).OrderBy(x=>x.AddressFamily).FirstOrDefault()
  138. ?.ToString();
  139. }
  140. if (!host.AddressList.Any(x =>
  141. (x.AddressFamily == AddressFamily.InterNetwork ||
  142. x.AddressFamily == AddressFamily.InterNetworkV6) && x.ToString().ToLower() ==
  143. _configuration.System.PreferredInterface.Trim().ToLower()))
  144. throw new ArgumentNullException(nameof(_configuration.System.PreferredInterface),
  145. "Mandatory preferred interface (or auto) for server identification.");
  146. // Pool directories structure
  147. EnsureDirectory(_configuration.System.PoolPathBase);
  148. EnsureDirectory(_fileSystem.Path.Combine(_configuration.System.PoolPathBase, _configuration.System.PoolPathDone));
  149. EnsureDirectory(_fileSystem.Path.Combine(_configuration.System.PoolPathBase, _configuration.System.PoolPathFail));
  150. EnsureDirectory(_fileSystem.Path.Combine(_configuration.System.PoolPathBase, _configuration.System.PoolPathPending));
  151. EnsureDirectory(_fileSystem.Path.Combine(_configuration.System.PoolPathBase, _configuration.System.PoolPathWorking));
  152. // Scenario structure
  153. EnsureDirectory(_configuration.System.ScenarioPathBase);
  154. if (_fileSystem.Directory.GetFiles(TranslatePath(_configuration.System.ScenarioPathBase), "*.*").Length == 0)
  155. LogWarn($"Scenario directory '{TranslatePath(_configuration.System.ScenarioPathBase)}' is empty.");
  156. LogInfo("Configuration validated.");
  157. }
  158. private string EnsureDirectory(string path)
  159. {
  160. var dir = FileUtils.EnsurePathEndsWithDirSeparator(_fileSystem, TranslatePath(path));
  161. if (!_fileSystem.Directory.Exists(dir))
  162. {
  163. _fileSystem.Directory.CreateDirectory(dir);
  164. LogDebug($"Directory '{dir}' created.");
  165. }
  166. if (!_fileSystem.Directory.Exists(dir))
  167. throw new FileNotFoundException($"Directory '{dir}' not found!");
  168. return dir;
  169. }
  170. private string TranslatePath(string path)
  171. {
  172. if (string.IsNullOrEmpty(path))
  173. return path;
  174. return path.Replace("{CD}", _fileSystem.Directory.GetCurrentDirectory());
  175. }
  176. private void StopAll(bool silently = false)
  177. {
  178. _wkPull.Stop(silently);
  179. _wkRetention.Stop(silently);
  180. _wkProcessing.Stop(silently);
  181. foreach (var process in _processes)
  182. process.Stop(silently);
  183. foreach (var process in _processes)
  184. process.Dispose();
  185. _processes.Clear();
  186. }
  187. #endregion
  188. }
  189. }