public async Task Pushing_for_slots_after_start_works_when_batch_size_is_reached() { var receivedItems = new ConcurrentQueue <List <int> >[4] { new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), }; var countDownEvent = new CountdownEvent(16); // choose insanely high push interval var completion = new MultiProducerConcurrentCompletion <int>(batchSize: 100, pushInterval: TimeSpan.FromDays(1), maxConcurrency: 4, numberOfSlots: 4); completion.Start((items, slot, state, token) => { receivedItems[slot].Enqueue(new List <int>(items)); // take a copy if (!countDownEvent.IsSet) { countDownEvent.Signal(); } return(Task.FromResult(0)); }); var numberOfItems = await PushConcurrentlyTwoThousandItemsInPackagesOfFiveHundredIntoFourSlots(completion); // we wait for 16 counts and then complete midway await Task.Run(() => countDownEvent.Wait(TimeSpan.FromSeconds(5))); await completion.Complete(); Assert.AreEqual(TriangularNumber(numberOfItems), Flatten(receivedItems).Sum(i => i)); }
public async Task Complete_works_even_when_push_interval_and_batch_size_not_reached() { var receivedItems = new ConcurrentQueue <List <int> >[4] { new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), }; // choose insanely high batchSize and pushInterval to force the loop hanging var completion = new MultiProducerConcurrentCompletion <int>(batchSize: 10000, pushInterval: TimeSpan.FromDays(1), maxConcurrency: 4, numberOfSlots: 4); completion.Start((items, slot, state, token) => { receivedItems[slot].Enqueue(new List <int>(items)); // take a copy return(Task.FromResult(0)); }); var numberOfItems = await PushConcurrentlyTwoThousandItemsInPackagesOfFiveHundredIntoFourSlots(completion); await completion.Complete(); var sumOfAllElementsSeenSoFar = Flatten(receivedItems).Sum(i => i); Assert.AreEqual(TriangularNumber(numberOfItems), sumOfAllElementsSeenSoFar); Assert.AreEqual(TriangularNumber(numberOfItems), Flatten(receivedItems).Sum(i => i), "Dispatcher complete brought more items than expected"); }
public async Task Pushing_and_complete_with_no_drain_without_start_empties_slots() { var pushedItems = new ConcurrentQueue <List <int> >[4] { new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), }; // choose insanely high batchSize to force push interval picking up all the content var completion = new MultiProducerConcurrentCompletion <int>(batchSize: 100, pushInterval: TimeSpan.FromMilliseconds(1), maxConcurrency: 4, numberOfSlots: 4); await PushConcurrentlyTwoThousandItemsInPackagesOfFiveHundredIntoFourSlots(completion); await completion.Complete(drain : false); var countDownEvent = new CountdownEvent(1); completion.Start((items, slot, state, token) => { pushedItems[slot].Enqueue(new List <int>(items)); // take a copy countDownEvent.Signal(); return(Task.FromResult(0)); }); completion.Push(1, slotNumber: 1); await Task.Run(() => countDownEvent.Wait(TimeSpan.FromSeconds(5))); await completion.Complete(); Assert.AreEqual(1, Flatten(pushedItems).Sum(i => i)); }
public void Initialize(EntityInfo entity, Func <IncomingMessageDetails, ReceiveContext, Task> callback, Func <Exception, Task> errorCallback, Func <ErrorContext, Task <ErrorHandleResult> > processingFailureCallback, int maximumConcurrency) { receiveMode = settings.Get <ReceiveMode>(WellKnownConfigurationKeys.Connectivity.MessageReceivers.ReceiveMode); incomingCallback = callback; this.errorCallback = errorCallback ?? EmptyErrorCallback; this.processingFailureCallback = processingFailureCallback; this.entity = entity; fullPath = entity.Path; if (entity.Type == EntityType.Subscription) { var topic = entity.RelationShips.First(r => r.Type == EntityRelationShipType.Subscription); fullPath = SubscriptionClient.FormatSubscriptionPath(topic.Target.Path, entity.Path); } var transportTransactionMode = settings.HasExplicitValue <TransportTransactionMode>() ? settings.Get <TransportTransactionMode>() : settings.SupportedTransactionMode(); wrapInScope = transportTransactionMode == TransportTransactionMode.SendsAtomicWithReceive; completionCanBeBatched = !wrapInScope; autoRenewTimeout = settings.Get <TimeSpan>(WellKnownConfigurationKeys.Connectivity.MessageReceivers.AutoRenewTimeout); numberOfClients = settings.Get <int>(WellKnownConfigurationKeys.Connectivity.NumberOfClientsPerEntity); var concurrency = maximumConcurrency / (double)numberOfClients; maxConcurrentCalls = concurrency > 1 ? (int)Math.Round(concurrency, MidpointRounding.AwayFromZero) : 1; if (Math.Abs(maxConcurrentCalls - concurrency) > 0) { logger.InfoFormat("The maximum concurrency on message receiver instance for '{0}' has been adjusted to '{1}', because the total maximum concurrency '{2}' wasn't divisable by the number of clients '{3}'", fullPath, maxConcurrentCalls, maximumConcurrency, numberOfClients); } internalReceivers = new IMessageReceiver[numberOfClients]; onMessageOptions = new OnMessageOptions[numberOfClients]; completion = new MultiProducerConcurrentCompletion <Guid>(1000, TimeSpan.FromSeconds(1), 6, numberOfClients); }
public async Task Pushing_for_slots_before_start_works_when_pushInterval_reached() { var receivedItems = new ConcurrentQueue <List <int> >[4] { new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), new ConcurrentQueue <List <int> >(), }; var countDownEvent = new CountdownEvent(4); // choose insanely high batchSize var completion = new MultiProducerConcurrentCompletion <int>(batchSize: 10000, pushInterval: TimeSpan.FromMilliseconds(1), maxConcurrency: 4, numberOfSlots: 4); var numberOfItems = await PushConcurrentlyTwoThousandItemsInPackagesOfFiveHundredIntoFourSlots(completion); completion.Start(async(items, slot, state, token) => { await Task.Yield(); receivedItems[slot].Enqueue(new List <int>(items)); // take a copy if (!countDownEvent.IsSet) { countDownEvent.Signal(); } }); await Task.Run(() => countDownEvent.Wait(TimeSpan.FromSeconds(5))); var sumOfAllElementsSeenSoFar = Flatten(receivedItems).Sum(i => i); await completion.Complete(); Assert.AreEqual(TriangularNumber(numberOfItems), sumOfAllElementsSeenSoFar); Assert.AreEqual(TriangularNumber(numberOfItems), Flatten(receivedItems).Sum(i => i), "Dispatcher complete brought more items than expected"); }
static async Task <int> PushConcurrentlyTwoThousandItemsInPackagesOfFiveHundredIntoFourSlots(MultiProducerConcurrentCompletion <int> completion) { var t1 = Task.Run(() => Parallel.For(1, 500, i => { completion.Push(slotNumber: 0, item: i); })); var t2 = Task.Run(() => Parallel.For(500, 1000, i => { completion.Push(slotNumber: 1, item: i); })); var t3 = Task.Run(() => Parallel.For(1000, 1500, i => { completion.Push(slotNumber: 2, item: i); })); await Task.WhenAll(t1, t2, t3); var numberOfItems = 2000; for (var i = 1500; i < numberOfItems + 1; i++) { completion.Push(slotNumber: 3, item: i); } return(numberOfItems); }