// Load rec source synchronously. Ideally rec source training would periodically check for cancellation // so that service can be stopped even if a rec source with massive startup time is loaded. But since // the service is stopping anyway, training takes place on a separate thread which is abandoned on cancellation. // For use on startup only, before calling Start(). public void LoadRecSource(DTO.LoadRecSourceRequest recSourceConfig, CancellationToken cancellationToken) { if (m_state == null) { throw new ObjectDisposedException("TcpRecService"); } if (m_listenerTask != null) { throw new InvalidOperationException("Can only load rec sources into TcpRecService before starting to listen on socket."); } try { // "Async" because of async locks m_state.LoadRecSourceAsync(recSourceConfig, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(); } catch (Exception ex) when(!(ex is OperationCanceledException)) { throw new Exception(string.Format("Error loading rec source {0}: {1}", recSourceConfig.Name, ex.Message), ex); } }
// Loads all configured rec sources into the rec service in parallel. // Does not return until complete or serviceStopToken is signaled. private static void LoadRecSources(TcpRecService recService, Config config, CancellationToken serviceStopToken) { if (config.RecSources.Count == 0) { Logging.Log.Info("No rec sources configured."); return; } Logging.Log.InfoFormat("Loading {0} rec sources.", config.RecSources.Count); List <ICancellableTask> recSourceLoadTasks = new List <ICancellableTask>(config.RecSources.Count); using (CancellationTokenSource anyTaskFaultedOrCanceled = new CancellationTokenSource()) using (CancellationTokenSource cancelTokenSource = CancellationTokenSource.CreateLinkedTokenSource(serviceStopToken, anyTaskFaultedOrCanceled.Token)) { foreach (DTO.LoadRecSourceRequest recSourceConfigX in config.RecSources) { DTO.LoadRecSourceRequest recSourceConfig = recSourceConfigX; // Don't capture the loop variable Task loadRecSourceTask = Task.Factory.StartNew(() => { recService.LoadRecSource(recSourceConfig, cancelTokenSource.Token); }, cancelTokenSource.Token); recSourceLoadTasks.Add(new CancellableTask(loadRecSourceTask, anyTaskFaultedOrCanceled)); } try { AsyncUtils.WhenAllCancelOnFirstExceptionDontWaitForCancellations(recSourceLoadTasks).ConfigureAwait(false).GetAwaiter().GetResult(); } catch (OperationCanceledException) { Logging.Log.Info("Canceled loading rec sources."); throw; } } recService.FinalizeRecSources(serviceStopToken); }