public void When_waiting_for_consumption_to_complete() { var exceptions = new ConcurrentBag <Exception>(); var numbers = new ConcurrentQueue <int>(); Action <int> work = n => { Thread.Sleep(50.Milliseconds()); numbers.Enqueue(n); }; using (var pcq = new ProducerConsumerQueue <int>(work, 1)) { pcq.OnException += (sender, exception) => exceptions.Add(exception); pcq.Add(1); pcq.Add(2); pcq.Add(3); pcq.CompleteAdding(); pcq.Completion.Result.ShouldBeTrue(); numbers.ShouldBe(new[] { 1, 2, 3 }); exceptions.ShouldBeEmpty(); pcq.Capacity.ShouldBe(-1); pcq.PendingCount.ShouldBe((uint)0); pcq.PendingItems.ShouldBeEmpty(); } }
public void DisposedQueueShouldCancelConsumersCorrectly() { Exception exceptionThrown = null; var consumed = new ConcurrentBag <int>(); var queue = new ProducerConsumerQueue <int>(i => { Thread.Sleep(50.Milliseconds()); consumed.Add(i); }, 1); queue.OnException += (sender, args) => { using (consumed.Lock(100.Milliseconds())) { exceptionThrown = args; } }; queue.Add(1); queue.Add(2); queue.Add(3); queue.Add(4); queue.Add(5); queue.CompleteAdding(); queue.Completion.Wait(500.Milliseconds()).ShouldBeTrue(); consumed.Count.ShouldBeGreaterThanOrEqualTo(2); Thread.Sleep(1.Seconds()); exceptionThrown.ShouldBeNull(); }
public void ThrownExceptionByMultipleWorkersShouldBePublishedCorrectly() { var exceptions = new ConcurrentQueue <Exception>(); Action <MyClass> consumer = x => { Task.Delay(50.Milliseconds()); throw new InvalidDataException("Something went wrong for: " + x.Id); }; var queue = new ProducerConsumerQueue <MyClass>(consumer, 2); queue.OnException += (sender, args) => { exceptions.Enqueue(args.InnerException); }; queue.Add(_getData(0)); queue.Add(_getData(1)); Task.Delay(100.Milliseconds()).Wait(); exceptions.Count.ShouldBe(2); exceptions.ShouldContain(e => e is InvalidDataException && e.Message.Equals("Something went wrong for: 0")); exceptions.ShouldContain(e => e is InvalidDataException && e.Message.Equals("Something went wrong for: 1")); }
public void ShutdownQueueAfterSomeAddsShouldResultInTheProcessOfAllAddedItemsBeforeDisposal() { var consumed = new ConcurrentBag <MyClass>(); Action <MyClass> consumer = x => { consumed.Add(x); }; var queue = new ProducerConsumerQueue <MyClass>(consumer, 1); ProducerConsumerQueueException thrownException = null; queue.OnException += (sender, args) => { thrownException = args; }; 5.Times(n => { queue.Add(_getData(n)); }); queue.CompleteAdding(); queue.Completion.Wait(10.Seconds()).ShouldBeTrue(); Action afterDisposedEnqueues = () => 3.Times(n => { queue.Add(_getData(n)); }); afterDisposedEnqueues.ShouldNotThrow(); Thread.Sleep(100); consumed.Count.ShouldBe(5); Thread.Sleep(1.Seconds()); thrownException.ShouldNotBeNull(); thrownException.Message.ShouldBe("Exception occurred when adding item."); }
public void DisposedQueueShouldNotAllowAddingNewItems() { var consumed = new ConcurrentBag <MyClass>(); Action <MyClass> consumer = x => { consumed.Add(x); }; var queue = new ProducerConsumerQueue <MyClass>(consumer, 1); ProducerConsumerQueueException thrownException = null; queue.OnException += (sender, args) => { thrownException = args; }; const int WorkItems = 10; for (var i = 0; i < 10; i++) { queue.Add(_getData(i)); } queue.CompleteAdding(); queue.Completion.Wait(5.Seconds()).ShouldBeTrue(); Thread.Sleep(50.Milliseconds()); consumed.Count.ShouldBe(WorkItems); Assert.DoesNotThrow(() => queue.Add(new MyClass())); Thread.Sleep(1.Seconds()); thrownException.ShouldNotBeNull(); thrownException.Message.ShouldBe("Exception occurred when adding item."); }
public void When_disposing_while_items_still_in_queue() { var exceptions = new List <Exception>(); var numbers = new List <int>(); Action <int> work = n => { Thread.Sleep(500.Milliseconds()); numbers.Add(n); }; var pcq = new ProducerConsumerQueue <int>(work, 1); pcq.OnException += (sender, exception) => exceptions.Add(exception); pcq.Add(1); pcq.Add(2); pcq.Add(3); pcq.Dispose(); pcq.Completion.Result.ShouldBeFalse(); numbers.ShouldBe(new[] { 1 }); exceptions.ShouldBeEmpty(); Should.Throw <ObjectDisposedException>(() => pcq.Capacity.ShouldBe(-1)) .Message.ShouldBe("The collection has been disposed.\r\nObject name: 'BlockingCollection'."); Should.Throw <ObjectDisposedException>(() => pcq.PendingCount.ShouldBe((uint)2)) .Message.ShouldBe("The collection has been disposed.\r\nObject name: 'BlockingCollection'."); Should.Throw <ObjectDisposedException>(() => pcq.PendingItems.ShouldBe(new[] { 2, 3 })) .Message.ShouldBe("The collection has been disposed.\r\nObject name: 'BlockingCollection'."); }
public void BlockingConsumerWithTwoWorkersShouldBlockOnlyOneItem() { var exceptionThrown = false; var consumed = new ConcurrentBag <MyClass>(); var counter = 0; Action <MyClass> consumer = x => { if (counter == 0) { counter++; Thread.Sleep(1.Minutes()); } consumed.Add(x); }; var queue = new ProducerConsumerQueue <MyClass>(consumer, 2); queue.OnException += (sender, args) => { using (consumed.Lock(100.Milliseconds())) { exceptionThrown = true; } }; 10.Times(n => queue.Add(_getData(n))); Thread.Sleep(100); exceptionThrown.ShouldBeFalse(); queue.PendingCount.ShouldBe <uint>(0); queue.Completion.Wait(500.Milliseconds()).ShouldBeFalse(); consumed.Count.ShouldBe(9); }
public void BlockingConsumerWithOneWorkerShouldBlockEverything() { var exceptionThrown = false; var consumed = new ConcurrentBag <MyClass>(); Action <MyClass> consumer = x => { Thread.Sleep(1.Minutes()); consumed.Add(x); }; var queue = new ProducerConsumerQueue <MyClass>(consumer, 1); queue.OnException += (sender, args) => { using (consumed.Lock(100.Milliseconds())) { exceptionThrown = true; } }; queue.PendingCount.ShouldBe <uint>(0); 10.Times(n => queue.Add(_getData(n))); Thread.Sleep(100.Milliseconds()); queue.PendingCount.ShouldBe <uint>(9); queue.Completion.Wait(600.Milliseconds()).ShouldBeFalse(); consumed.Count.ShouldBe(0); exceptionThrown.ShouldBeFalse(); }
public void ThrownExceptionBySingleWorkerShouldBePublishedCorrectly() { Exception exception = null; var consumed = new ConcurrentBag <MyClass>(); Action <MyClass> consumer = x => { if (x.Id % 2 != 0) { throw new InvalidDataException("Something went wrong"); } consumed.Add(x); }; var queue = new ProducerConsumerQueue <MyClass>(consumer, 1); queue.OnException += (sender, args) => { exception = args; }; queue.Add(_getData(0)); Thread.Sleep(50); consumed.Count.ShouldBe(1); exception.ShouldBeNull("Because no exception has occurred yet."); queue.Add(_getData(1)); Thread.Sleep(50); consumed.Count.ShouldBe(1); exception.ShouldNotBeNull("Because an exception must have occurred."); exception.ShouldBeOfType <ProducerConsumerQueueException>() .Message.ShouldBe("Exception occurred."); exception.InnerException .ShouldBeOfType <InvalidDataException>() .Message.ShouldBe("Something went wrong"); }
public static IDictionary <string, uint> GetTopWordsProducerConsumerEasier(FileInfo InputFile, char[] Separators, uint TopCount) { // Limitations const int WorkerCount = 12; const int BoundedCapacity = 10000; var result = new ConcurrentDictionary <string, uint>(StringComparer.InvariantCultureIgnoreCase); // Declare the worker Action <string> work = line => { // Loop through words in line, filter seperators foreach (var word in line.Split(Separators, StringSplitOptions.RemoveEmptyEntries)) { // Valid word if (!TrackWordsClass.IsValidWord(word)) { continue; } // Update word list result.AddOrUpdate(word, 1, (key, oldVal) => oldVal + 1); } }; // Setup the queue var pcq = new ProducerConsumerQueue <string>(work, WorkerCount, BoundedCapacity); pcq.OnException += (sender, ex) => Console.WriteLine("Oooops: " + ex.Message); // Begin producing foreach (var line in File.ReadLines(InputFile.FullName)) { pcq.Add(line); } pcq.CompleteAdding(); // End of producing // Wait for workers to finish their work pcq.Completion.Wait(); // Return ordered dictionary return(result .OrderByDescending(kv => kv.Value) .Take((int)TopCount) .ToDictionary(kv => kv.Key, kv => kv.Value)); }
public void ConsumerWithOneWorkerShouldProcessEveryAddedItems() { Exception exceptionThrown = null; var consumed = new ConcurrentBag <MyClass>(); Action <MyClass> consumer = x => { consumed.Add(x); }; var queue = new ProducerConsumerQueue <MyClass>(consumer, 1); queue.OnException += (sender, args) => { using (consumed.Lock(100.Milliseconds())) { exceptionThrown = args; } }; 10.Times(n => queue.Add(_getData(n))); queue.CompleteAdding(); queue.Completion.Wait(100.Milliseconds()).ShouldBeTrue(); consumed.Count.ShouldBe(10); exceptionThrown.ShouldBeNull(); }