public YASLServer(ServerConfiguration serverConfiguration) { TokenSource = new CancellationTokenSource(); // create inputs foreach (KeyValuePair <string, QueueDefinition> queueCfg in serverConfiguration.Queues) { MasterQueue newQueue = new MasterQueue(TokenSource.Token); masterQueues.Add(queueCfg.Key, new Tuple <MasterQueue, Thread>(newQueue, new Thread(newQueue.GetWorker()))); } // create queues foreach (KeyValuePair <string, InputDefinition> inputCfg in serverConfiguration.Inputs) { InputDefinition inputDef = inputCfg.Value; Type inputModuleType = GetModuleAssembly(inputDef).GetType(inputDef.ManagedTypeName); IInputModule newModule = (IInputModule)Activator.CreateInstance(inputModuleType); newModule.Initialize(inputDef.ConfigurationJSON, TokenSource.Token, masterQueues.Where(z => serverConfiguration.Queues.Where(x => x.Value.Inputs.Contains(inputCfg.Key)).Select(y => y.Key).Contains(z.Key)).Select(t => t.Value.Item1)); inputModules.Add(inputCfg.Key, new Tuple <IInputModule, Thread>(newModule, new Thread(newModule.GetWorker()))); } }
private void Runner() { ThreadStart ModuleEntryPoint = null; bool finishedSuccessfully = true; int moduleFailureCount = 0; DateTime failureResetTimer = DateTime.UtcNow; do { // create and initialize module while (ModuleEntryPoint == null) { try { CancellationTokenSource?.Dispose(); CancellationTokenSource = new CancellationTokenSource(); CancellationToken = CancellationTokenSource.Token; InputModule = Server.CreateModule <IInputModule>(ModuleDefinition); InputModule.LoadConfiguration(ModuleConfiguration); InputModule.SetMessageSender(MessageAcceptor); InputModule.Initialize(); ModuleEntryPoint = InputModule.GetWorker(CancellationToken); failureResetTimer = DateTime.UtcNow; } catch (Exception e) { Server.Logger?.LogEvent(this, Severity.Error, "InputModule", $"Failed to re/create '{ModuleKey}'. Next retry in {ModuleReloadTimeoutSeconds} seconds.", e); ModuleEntryPoint = null; // pause before next attempt for (int waitCount = 0; waitCount < 100; waitCount++) { if (CancellationToken.IsCancellationRequested) { break; } Thread.Sleep(ModuleReloadTimeoutSeconds * 10); // effectively * 1000, i.e. seconds => milliseconds } if (CancellationToken.IsCancellationRequested && IsConfigurationReloadRequested) { continue; } // if canceled not for reload, and still unable to create, just mark completed and exit if (CancellationToken.IsCancellationRequested) { WorkCompleted.Set(); return; } } } // working try { ModuleEntryPoint.Invoke(); // ModuleEntryPoint != null, see above if (IsConfigurationReloadRequested) { IsConfigurationReloadRequested = false; try { InputModule.Destroy(); } catch { } // to avoid Invoke() catcher ModuleEntryPoint = null; // to initiate module load } finishedSuccessfully = true; if (CancellationToken.IsCancellationRequested) { break; } } catch (OperationCanceledException) { break; } catch (Exception e) { if (DateTime.UtcNow.Subtract(failureResetTimer).TotalSeconds > 10 * ModuleReloadTimeoutSeconds) { failureResetTimer = DateTime.UtcNow; moduleFailureCount = 0; } Server.Logger.LogEvent(InputModule, Severity.Error, "InputModule", $"Unexpected input module failure. That's happened {moduleFailureCount + 1} times in the row.", e); finishedSuccessfully = false; Server.Logger.LogEvent(this, Severity.Error, "InputModule", $"Recreating input module. Next retry in {ModuleReloadTimeoutSeconds * moduleFailureCount} seconds."); if (moduleFailureCount > 0) { Thread.Sleep(ModuleReloadTimeoutSeconds * moduleFailureCount * 1000); // pause before next attempt } // re-initialize the module try { InputModule.Destroy(); } catch { } ModuleEntryPoint = null; moduleFailureCount++; } } while (!finishedSuccessfully && !CancellationToken.IsCancellationRequested); // All done, but let's drain the queue while (AttachedQueue.Count > 0) { Thread.Sleep(5); } WorkCompleted.Set(); }