public void EnsureThreadedTaskSchedulerProcessesBeforeDispose() { int runCount = 0; const int target_count = 128; using (var taskScheduler = new ThreadedTaskScheduler(4, "test")) { for (int i = 0; i < target_count; i++) { Task.Factory.StartNew(() => { Interlocked.Increment(ref runCount); Thread.Sleep(100); }, default, TaskCreationOptions.HideScheduler, taskScheduler);
public ThreadedTaskSchedulerDebugView(ThreadedTaskScheduler scheduler) { Scheduler = scheduler ?? ThrowHelper.ThrowArgumentNullException <ThreadedTaskScheduler>(nameof(scheduler)); }
/// <summary> /// Start running the queue. /// </summary> /// <param name="cancellation">An optional cancellation token.</param> public void Run(CancellationToken cancellation = default) { using (new Timer(_ => outputStats(), null, TimeSpan.Zero, TimeSpan.FromSeconds(5))) using (var cts = new GracefulShutdownSource(cancellation)) { Console.WriteLine($"Starting queue processing (Backlog of {GetQueueSize()}).."); using (var threadPool = new ThreadedTaskScheduler(Environment.ProcessorCount, "workers")) { var database = redis.GetDatabase(); while (!cts.Token.IsCancellationRequested) { if (consecutiveErrors > config.ErrorThreshold) { throw new Exception("Error threshold exceeded, shutting down"); } T item = null; try { if (totalInFlight > config.MaxInFlightItems || consecutiveErrors > config.ErrorThreshold) { Thread.Sleep(config.TimeBetweenPolls); continue; } var redisValue = database.ListRightPop(inputQueueName); if (!redisValue.HasValue) { Thread.Sleep(config.TimeBetweenPolls); continue; } Interlocked.Increment(ref totalDequeued); DogStatsd.Increment("total_dequeued"); item = JsonConvert.DeserializeObject <T>(redisValue); // individual processing should not be cancelled as we have already grabbed from the queue. Task.Factory.StartNew(() => { ProcessResult(item); }, CancellationToken.None, TaskCreationOptions.HideScheduler, threadPool) .ContinueWith(t => { if (t.Exception == null) { Interlocked.Increment(ref totalProcessed); // ReSharper disable once AccessToDisposedClosure DogStatsd.Increment("total_processed"); Interlocked.Exchange(ref consecutiveErrors, 0); } else { Interlocked.Increment(ref totalErrors); // ReSharper disable once AccessToDisposedClosure DogStatsd.Increment("total_errors"); Interlocked.Increment(ref consecutiveErrors); Console.WriteLine($"Error processing {item}: {t.Exception}"); attemptRetry(item); } }, CancellationToken.None); } catch (Exception e) { Interlocked.Increment(ref consecutiveErrors); Console.WriteLine($"Error processing from queue: {e}"); attemptRetry(item); } } Console.WriteLine("Shutting down.."); } } DogStatsd.Dispose(); outputStats(); }
public ThreadedTaskSchedulerDebugView(ThreadedTaskScheduler scheduler) { Scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler)); }