Exemple #1
0
        public async Task Receive_StopProcessing(int numThreads)
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(
                             enablePartitioning: false,
                             enableSession: false))
            {
                await using var sender = new ServiceBusSenderClient(
                                TestEnvironment.ServiceBusConnectionString,
                                scope.QueueName);
                int numMessages = 50;
                await sender.SendBatchAsync(GetMessages(numMessages));

                await using var processor = new ServiceBusProcessorClient(
                                TestEnvironment.ServiceBusConnectionString,
                                scope.QueueName);
                int messageProcessedCt = 0;

                // stop processing halfway through
                int stopAfterMessagesCt = numMessages / 2;
                var options             = new ProcessingOptions()
                {
                    MaxConcurrentCalls = numThreads
                };

                TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);
                processor.ProcessMessageAsync += ProcessMessage;
                processor.ProcessErrorAsync   += ExceptionHandler;
                await processor.StartProcessingAsync(options);

                async Task ProcessMessage(ServiceBusMessage message, ServiceBusSession session)
                {
                    Interlocked.Increment(ref messageProcessedCt);
                    if (messageProcessedCt == stopAfterMessagesCt)
                    {
                        await processor.StopProcessingAsync();

                        tcs.TrySetResult(true);
                    }
                }

                await tcs.Task;
                var remainingCt = 0;
                var receiver    = new ServiceBusReceiverClient(TestEnvironment.ServiceBusConnectionString, scope.QueueName);

                foreach (ServiceBusMessage message in await receiver.ReceiveBatchAsync(numMessages))
                {
                    remainingCt++;
                }

                // can't assert on the exact amount processed due to threads that
                // are already in flight when calling StopProcessingAsync, but we can at least verify that there are remaining messages
                Assert.IsTrue(remainingCt > 0);
                Assert.IsTrue(messageProcessedCt < numMessages);
            }
        }
Exemple #2
0
        public async Task Receive_Event(int numThreads)
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(
                             enablePartitioning: false,
                             enableSession: false))
            {
                await using var sender = new ServiceBusSenderClient(
                                TestEnvironment.ServiceBusConnectionString,
                                scope.QueueName);

                // use double the number of threads so we can make sure we test that we don't
                // retrieve more messages than expected when there are more messages available
                await sender.SendBatchAsync(GetMessages(numThreads * 2));

                await using var processor = new ServiceBusProcessorClient(
                                TestEnvironment.ServiceBusConnectionString,
                                scope.QueueName);
                int messageCt = 0;

                var options = new ProcessingOptions()
                {
                    MaxConcurrentCalls = numThreads
                };

                TaskCompletionSource <bool>[] completionSources = Enumerable
                                                                  .Range(0, numThreads)
                                                                  .Select(index => new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously))
                                                                  .ToArray();
                var completionSourceIndex = -1;

                processor.ProcessMessageAsync += ProcessMessage;
                processor.ProcessErrorAsync   += ExceptionHandler;
                await processor.StartProcessingAsync(options);

                async Task ProcessMessage(ServiceBusMessage message, ServiceBusSession session)
                {
                    await processor.CompleteAsync(message.SystemProperties.LockToken);

                    Interlocked.Increment(ref messageCt);
                    var setIndex = Interlocked.Increment(ref completionSourceIndex);

                    completionSources[setIndex].TrySetResult(true);
                }

                await Task.WhenAll(completionSources.Select(source => source.Task));

                // we complete each thread after one message being processed, so the total number of messages
                // processed should equal the number of threads
                Assert.AreEqual(numThreads, messageCt);
            }
        }
        public async Task Process_Event_Consumes_All_Messages(int numThreads)
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(
                             enablePartitioning: false,
                             enableSession: true))
            {
                await using var sender = new ServiceBusSenderClient(
                                TestEnvironment.ServiceBusConnectionString,
                                scope.QueueName);

                // send 1 message for each thread and use a different session for each message
                ConcurrentDictionary <string, bool> sessions = new ConcurrentDictionary <string, bool>();
                for (int i = 0; i < numThreads; i++)
                {
                    var sessionId = Guid.NewGuid().ToString();
                    await sender.SendAsync(GetMessage(sessionId));

                    sessions.TryAdd(sessionId, true);
                }

                var clientOptions = new ServiceBusProcessorClientOptions()
                {
                    IsSessionEntity = true,
                    ReceiveMode     = ReceiveMode.ReceiveAndDelete,
                    RetryOptions    = new ServiceBusRetryOptions()
                    {
                        // to prevent the receive batch from taking a long time when we
                        // expect it to fail
                        MaximumRetries = 0,
                        TryTimeout     = TimeSpan.FromSeconds(5)
                    }
                };
                await using var processor = new ServiceBusProcessorClient(
                                TestEnvironment.ServiceBusConnectionString,
                                scope.QueueName,
                                clientOptions);
                int messageCt = 0;

                var options = new ProcessingOptions()
                {
                    MaxConcurrentCalls = numThreads
                };

                TaskCompletionSource <bool> taskCompletionSource = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);

                processor.ProcessMessageAsync += ProcessMessage;
                processor.ProcessErrorAsync   += ExceptionHandler;
                await processor.StartProcessingAsync(options);

                async Task ProcessMessage(ServiceBusMessage message, ServiceBusSession session)
                {
                    await processor.CompleteAsync(message.SystemProperties.LockToken);

                    sessions.TryRemove(message.SessionId, out bool _);
                    Assert.AreEqual(message.SessionId, await session.GetSessionIdAsync());
                    Assert.IsNotNull(await session.GetLockedUntilUtcAsync());
                    var ct = Interlocked.Increment(ref messageCt);

                    if (ct == numThreads)
                    {
                        taskCompletionSource.SetResult(true);
                    }
                }

                await taskCompletionSource.Task;


                // we only give each thread enough time to process one message, so the total number of messages
                // processed should equal the number of threads
                Assert.AreEqual(numThreads, messageCt);

                // we should have received messages from each of the sessions
                Assert.AreEqual(0, sessions.Count);

                // try receiving to verify empty
                // since all the messages are gone and we are using sessions, we won't actually
                // be able to open the Receive link
                await using var receiver = new ServiceBusReceiverClient(
                                TestEnvironment.ServiceBusConnectionString,
                                scope.QueueName);
                Assert.That(async() => await receiver.ReceiveBatchAsync(numThreads), Throws.Exception);
            }
        }
        public async Task Process_Event_SessionId(int numThreads)
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(
                             enablePartitioning: false,
                             enableSession: true))
            {
                await using var sender = new ServiceBusSenderClient(
                                TestEnvironment.ServiceBusConnectionString,
                                scope.QueueName);

                // send 1 message for each thread and use a different session for each message
                ConcurrentDictionary <string, bool> sessions = new ConcurrentDictionary <string, bool>();
                string sessionId = null;
                for (int i = 0; i < numThreads; i++)
                {
                    sessionId = Guid.NewGuid().ToString();
                    await sender.SendAsync(GetMessage(sessionId));

                    sessions.TryAdd(sessionId, true);
                }

                var clientOptions = new ServiceBusProcessorClientOptions()
                {
                    // just use the last sessionId from the loop above
                    SessionId       = sessionId,
                    IsSessionEntity = true,
                };

                await using var processor = new ServiceBusProcessorClient(
                                TestEnvironment.ServiceBusConnectionString,
                                scope.QueueName,
                                clientOptions);
                int messageCt = 0;

                var options = new ProcessingOptions()
                {
                    MaxConcurrentCalls = numThreads
                };

                TaskCompletionSource <bool>[] completionSources = Enumerable
                                                                  .Range(0, numThreads)
                                                                  .Select(index => new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously))
                                                                  .ToArray();
                var completionSourceIndex = -1;

                processor.ProcessMessageAsync += ProcessMessage;
                processor.ProcessErrorAsync   += ExceptionHandler;
                await processor.StartProcessingAsync(options);

                async Task ProcessMessage(ServiceBusMessage message, ServiceBusSession session)
                {
                    await processor.CompleteAsync(message.SystemProperties.LockToken);

                    Interlocked.Increment(ref messageCt);
                    sessions.TryRemove(message.SessionId, out bool _);
                    Assert.AreEqual(sessionId, message.SessionId);
                    Assert.AreEqual(sessionId, await session.GetSessionIdAsync());
                    Assert.IsNotNull(await session.GetLockedUntilUtcAsync());
                    var setIndex = Interlocked.Increment(ref completionSourceIndex);

                    completionSources[setIndex].TrySetResult(true);
                }

                await Task.WhenAny(completionSources.Select(source => source.Task));

                // although we are allowing concurrent calls,
                // since we are specifying a specific session, the
                // concurrency won't really work as only one receiver can be linked to the session; TODO may want to add validation for this
                Assert.AreEqual(1, messageCt);

                // we should have received messages from only the specified session
                Assert.AreEqual(numThreads - 1, sessions.Count);
            }
        }
        public async Task Process_Event(int numThreads)
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(
                             enablePartitioning: false,
                             enableSession: true))
            {
                await using var sender = new ServiceBusSenderClient(
                                TestEnvironment.ServiceBusConnectionString,
                                scope.QueueName);

                // send 1 message for each thread and use a different session for each message
                ConcurrentDictionary <string, bool> sessions = new ConcurrentDictionary <string, bool>();
                for (int i = 0; i < numThreads; i++)
                {
                    var sessionId = Guid.NewGuid().ToString();
                    await sender.SendAsync(GetMessage(sessionId));

                    sessions.TryAdd(sessionId, true);
                }

                var clientOptions = new ServiceBusProcessorClientOptions()
                {
                    IsSessionEntity = true,
                    ReceiveMode     = ReceiveMode.ReceiveAndDelete
                };
                await using var processor = new ServiceBusProcessorClient(
                                TestEnvironment.ServiceBusConnectionString,
                                scope.QueueName,
                                clientOptions);
                int messageCt = 0;

                var options = new ProcessingOptions()
                {
                    MaxConcurrentCalls = numThreads
                };

                TaskCompletionSource <bool>[] completionSources = Enumerable
                                                                  .Range(0, numThreads)
                                                                  .Select(index => new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously))
                                                                  .ToArray();

                var completionSourceIndex = -1;

                processor.ProcessMessageAsync += ProcessMessage;
                processor.ProcessErrorAsync   += ExceptionHandler;
                await processor.StartProcessingAsync(options);

                async Task ProcessMessage(ServiceBusMessage message, ServiceBusSession session)
                {
                    await processor.CompleteAsync(message.SystemProperties.LockToken);

                    Interlocked.Increment(ref messageCt);
                    sessions.TryRemove(message.SessionId, out bool _);
                    Assert.AreEqual(message.SessionId, await session.GetSessionIdAsync());
                    Assert.IsNotNull(await session.GetLockedUntilUtcAsync());
                    var setIndex = Interlocked.Increment(ref completionSourceIndex);

                    completionSources[setIndex].TrySetResult(true);
                }

                await Task.WhenAll(completionSources.Select(source => source.Task));

                // we only give each thread enough time to process one message, so the total number of messages
                // processed should equal the number of threads
                Assert.AreEqual(numThreads, messageCt);

                // we should have received messages from each of the sessions
                Assert.AreEqual(0, sessions.Count);
            }
        }