public void CanRemoveHandlerThatHasBeenAdded()
        {
            var processor = new ServiceBusSessionProcessor(
                GetMockedConnection(),
                "entityPath",
                new ServiceBusPlugin[] { },
                new ServiceBusSessionProcessorOptions());

            Func <ProcessSessionMessageEventArgs, Task> eventHandler        = eventArgs => Task.CompletedTask;
            Func <ProcessErrorEventArgs, Task>          errorHandler        = eventArgs => Task.CompletedTask;
            Func <ProcessSessionEventArgs, Task>        sessionInitHandler  = eventArgs => Task.CompletedTask;
            Func <ProcessSessionEventArgs, Task>        sessionCloseHandler = eventArgs => Task.CompletedTask;

            processor.ProcessMessageAsync      += eventHandler;
            processor.ProcessErrorAsync        += errorHandler;
            processor.SessionInitializingAsync += sessionInitHandler;
            processor.SessionClosingAsync      += sessionCloseHandler;

            Assert.That(() => processor.ProcessMessageAsync      -= eventHandler, Throws.Nothing);
            Assert.That(() => processor.ProcessErrorAsync        -= errorHandler, Throws.Nothing);
            Assert.That(() => processor.SessionInitializingAsync -= sessionInitHandler, Throws.Nothing);
            Assert.That(() => processor.SessionClosingAsync      -= sessionCloseHandler, Throws.Nothing);

            // Assert that handlers can be added again.

            Assert.That(() => processor.ProcessMessageAsync      += eventHandler, Throws.Nothing);
            Assert.That(() => processor.ProcessErrorAsync        += errorHandler, Throws.Nothing);
            Assert.That(() => processor.SessionInitializingAsync += sessionInitHandler, Throws.Nothing);
            Assert.That(() => processor.SessionClosingAsync      += sessionCloseHandler, Throws.Nothing);
        }
        public void CannotRemoveHandlerThatHasNotBeenAdded()
        {
            var processor = new ServiceBusSessionProcessor(
                GetMockedConnection(),
                "entityPath",
                new ServiceBusPlugin[] { },
                new ServiceBusSessionProcessorOptions());

            // First scenario: no handler has been set.

            Assert.That(() => processor.ProcessMessageAsync      -= eventArgs => Task.CompletedTask, Throws.InstanceOf <ArgumentException>());
            Assert.That(() => processor.ProcessErrorAsync        -= eventArgs => Task.CompletedTask, Throws.InstanceOf <ArgumentException>());
            Assert.That(() => processor.SessionInitializingAsync -= eventArgs => Task.CompletedTask, Throws.InstanceOf <ArgumentException>());
            Assert.That(() => processor.SessionClosingAsync      -= eventArgs => Task.CompletedTask, Throws.InstanceOf <ArgumentException>());

            // Second scenario: there is a handler set, but it's not the one we are trying to remove.

            processor.ProcessMessageAsync      += eventArgs => Task.CompletedTask;
            processor.ProcessErrorAsync        += eventArgs => Task.CompletedTask;
            processor.SessionInitializingAsync += eventArgs => Task.CompletedTask;
            processor.SessionClosingAsync      += eventArgs => Task.CompletedTask;

            Assert.That(() => processor.ProcessMessageAsync      -= eventArgs => Task.CompletedTask, Throws.InstanceOf <ArgumentException>());
            Assert.That(() => processor.ProcessErrorAsync        -= eventArgs => Task.CompletedTask, Throws.InstanceOf <ArgumentException>());
            Assert.That(() => processor.SessionInitializingAsync -= eventArgs => Task.CompletedTask, Throws.InstanceOf <ArgumentException>());
            Assert.That(() => processor.SessionClosingAsync      -= eventArgs => Task.CompletedTask, Throws.InstanceOf <ArgumentException>());
        }
        public async Task SessionProcessorActivities()
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
            {
                using var listener = new TestDiagnosticListener(EntityScopeFactory.DiagnosticNamespace);
                var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);
                ServiceBusSender sender = client.CreateSender(scope.QueueName);
                var messageCt           = 2;
                var msgs = GetMessages(messageCt, "sessionId");
                await sender.SendMessagesAsync(msgs);

                Activity[] sendActivities = AssertSendActivities(false, sender, msgs, listener);

                ServiceBusSessionProcessor processor = client.CreateSessionProcessor(scope.QueueName,
                                                                                     new ServiceBusSessionProcessorOptions
                {
                    AutoComplete          = false,
                    MaxReceiveWaitTime    = TimeSpan.FromSeconds(10),
                    MaxConcurrentSessions = 1
                });
                TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool>();
                int processedMsgCt = 0;
                processor.ProcessMessageAsync += args =>
                {
                    processedMsgCt++;
                    if (processedMsgCt == messageCt)
                    {
                        tcs.SetResult(true);
                    }
                    return(Task.CompletedTask);
                };
                processor.ProcessErrorAsync += ExceptionHandler;
                await processor.StartProcessingAsync();

                await tcs.Task;
                await processor.StopProcessingAsync();

                for (int i = 0; i < messageCt; i++)
                {
                    (string Key, object Value, DiagnosticListener)receiveStart = listener.Events.Dequeue();
                    (string Key, object Value, DiagnosticListener)receiveStop  = listener.Events.Dequeue();
                    (string Key, object Value, DiagnosticListener)processStart = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.ProcessSessionMessageActivityName + ".Start", processStart.Key);
                    Activity processActivity = (Activity)processStart.Value;
                    AssertCommonTags(processActivity, processor.EntityPath, processor.FullyQualifiedNamespace);
                    CollectionAssert.Contains(
                        processActivity.Tags,
                        new KeyValuePair <string, string>(
                            DiagnosticProperty.MessageIdAttribute,
                            msgs[i].MessageId));
                    CollectionAssert.Contains(
                        processActivity.Tags,
                        new KeyValuePair <string, string>(
                            DiagnosticProperty.SessionIdAttribute,
                            msgs[i].SessionId));
                    (string Key, object Value, DiagnosticListener)processStop = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.ProcessSessionMessageActivityName + ".Stop", processStop.Key);
                }
            };
        }
Ejemplo n.º 4
0
 public CustomSessionMessageProcessor(
     ServiceBusSessionProcessor sessionProcessor,
     ILogger logger)
     : base(sessionProcessor)
 {
     _logger = logger;
 }
Ejemplo n.º 5
0
        static async Task ReceiveSessionMessageAsync()
        {
            Console.WriteLine("=========================================================");
            Console.WriteLine("Press ENTER key to exit after receiving all the messages.");
            Console.WriteLine("=========================================================");
            var options = new ServiceBusSessionProcessorOptions {
                AutoCompleteMessages         = false,
                MaxConcurrentSessions        = 2,
                MaxConcurrentCallsPerSession = 2
            };

            await using ServiceBusSessionProcessor processor = string.IsNullOrWhiteSpace(SubscriptionName) ?
                                                               srv.CreateSessionProcessor(QueueOrTopicName, options) :
                                                               srv.CreateSessionProcessor(QueueOrTopicName, SubscriptionName, options);
            processor.ProcessMessageAsync += async(arg) => {
                Console.WriteLine($"Received message: {arg.SessionId} SequenceNumber: {arg.Message.SequenceNumber} Body: {Encoding.UTF8.GetString(arg.Message.Body)}");
                if (AbandonarMultiplosDe > 0 && arg.Message.SequenceNumber % AbandonarMultiplosDe == 0)
                {
                    await arg.AbandonMessageAsync(arg.Message);
                }
                else
                {
                    await arg.CompleteMessageAsync(arg.Message);
                }
            };
            processor.ProcessErrorAsync += ExceptionReceivedHandler;
            await processor.StartProcessingAsync();

            Console.Read();
            Console.WriteLine("Exit ...");
            await processor.CloseAsync();
        }
Ejemplo n.º 6
0
 public Task StartProcessingAsync(CancellationToken cancellationToken = default)
 {
     return(_serviceBusProcessorAsObject switch
     {
         ServiceBusProcessor serviceBusProcessor => serviceBusProcessor.StartProcessingAsync(cancellationToken),
         ServiceBusSessionProcessor serviceBusSessionProcessor => serviceBusSessionProcessor.StartProcessingAsync(cancellationToken),
         _ => Task.CompletedTask
     });
Ejemplo n.º 7
0
        public void MustSetMessageHandler()
        {
            var processor = new ServiceBusSessionProcessor(
                GetMockedReceiverConnection(),
                "entityPath",
                new ServiceBusSessionProcessorOptions());

            Assert.That(async() => await processor.StartProcessingAsync(), Throws.InstanceOf <InvalidOperationException>());
        }
Ejemplo n.º 8
0
        public void MustSetErrorHandler()
        {
            var processor = new ServiceBusSessionProcessor(
                GetMockedConnection(),
                "entityPath",
                new ServiceBusSessionProcessorOptions());

            processor.ProcessMessageAsync += eventArgs => Task.CompletedTask;

            Assert.That(async() => await processor.StartProcessingAsync(), Throws.InstanceOf <InvalidOperationException>());
        }
Ejemplo n.º 9
0
        public void CannotAddNullHandler()
        {
            var processor = new ServiceBusSessionProcessor(
                GetMockedReceiverConnection(),
                "entityPath",
                new ServiceBusSessionProcessorOptions());

            Assert.That(() => processor.ProcessMessageAsync      += null, Throws.InstanceOf <ArgumentNullException>());
            Assert.That(() => processor.ProcessErrorAsync        += null, Throws.InstanceOf <ArgumentNullException>());
            Assert.That(() => processor.SessionInitializingAsync += null, Throws.InstanceOf <ArgumentNullException>());
            Assert.That(() => processor.SessionClosingAsync      += null, Throws.InstanceOf <ArgumentNullException>());
        }
Ejemplo n.º 10
0
        public void CannotAddTwoHandlersToTheSameEvent()
        {
            var processor = new ServiceBusSessionProcessor(
                GetMockedReceiverConnection(),
                "entityPath",
                new ServiceBusSessionProcessorOptions());

            processor.ProcessMessageAsync      += eventArgs => Task.CompletedTask;
            processor.ProcessErrorAsync        += eventArgs => Task.CompletedTask;
            processor.SessionInitializingAsync += eventArgs => Task.CompletedTask;
            processor.SessionClosingAsync      += eventArgs => Task.CompletedTask;

            Assert.That(() => processor.ProcessMessageAsync      += eventArgs => Task.CompletedTask, Throws.InstanceOf <NotSupportedException>());
            Assert.That(() => processor.ProcessErrorAsync        += eventArgs => Task.CompletedTask, Throws.InstanceOf <NotSupportedException>());
            Assert.That(() => processor.SessionInitializingAsync += eventArgs => Task.CompletedTask, Throws.InstanceOf <NotSupportedException>());
            Assert.That(() => processor.SessionClosingAsync      += eventArgs => Task.CompletedTask, Throws.InstanceOf <NotSupportedException>());
        }
Ejemplo n.º 11
0
        public static async Task RunSessionProcessor(string connectionString, string queueName, TimeSpan timeSpan)
        {
            // since ServiceBusClient implements IAsyncDisposable we create it with "await using"
            await using var client = new ServiceBusClient(connectionString);

            // get the options to use for configuring the processor
            var options = new ServiceBusSessionProcessorOptions
            {
                // By default after the message handler returns, the processor will complete the message
                // If I want more fine-grained control over settlement, I can set this to false.
                AutoCompleteMessages = false,

                // I can also allow for processing multiple sessions
                MaxConcurrentSessions = 5,

                // By default, there will be a single concurrent call per session. I can
                // increase that here to enable parallel processing within each session.
                MaxConcurrentCallsPerSession = 2
            };

            // create a processor that we can use to process the messages
            ServiceBusSessionProcessor processor = client.CreateSessionProcessor(queueName, options);

            processor.ProcessMessageAsync += MessageHandler;
            processor.ProcessErrorAsync   += ErrorHandler;

            await processor.StartProcessingAsync();

            // since the message handler will run in a background thread, in order to prevent
            // this sample from terminating immediately
            DateTime endProcessing = DateTime.Now.Add(timeSpan);

            while (DateTime.Now < endProcessing)
            {
                await Task.Delay(100);
            }

            // stop processing once the task completion source was completed.
            await processor.StopProcessingAsync();
        }
Ejemplo n.º 12
0
        public void ConcurrencyUpdateManager_Sessions_UpdatesProcessorConcurrency()
        {
            var concurrencyOptions = new OptionsWrapper <ConcurrencyOptions>(new ConcurrencyOptions {
                DynamicConcurrencyEnabled = true
            });
            var concurrencyManager = new ConcurrencyManager(concurrencyOptions, _loggerFactory, _mockConcurrencyThrottleManager.Object);

            _mockConcurrencyThrottleManager.Setup(p => p.GetStatus()).Returns(new ConcurrencyThrottleAggregateStatus {
                State = ThrottleState.Disabled
            });
            ServiceBusSessionProcessor sessionProcessor = _client.CreateSessionProcessor(_entityPath, new ServiceBusSessionProcessorOptions {
                MaxConcurrentSessions = 1, MaxConcurrentCallsPerSession = 1
            });
            Lazy <SessionMessageProcessor> sessionMessageProcessor = new Lazy <SessionMessageProcessor>(() => new SessionMessageProcessor(sessionProcessor));
            ILogger logger = _loggerFactory.CreateLogger("test");

            ServiceBusListener.ConcurrencyUpdateManager concurrencyUpdateManager = new ServiceBusListener.ConcurrencyUpdateManager(concurrencyManager, null, sessionMessageProcessor, true, _functionId, logger);

            // when no messages are being processed, concurrency is not adjusted
            Assert.AreEqual(1, sessionProcessor.MaxConcurrentSessions);
            Assert.AreEqual(1, sessionProcessor.MaxConcurrentCallsPerSession);
            SetFunctionCurrentConcurrency(concurrencyManager, _functionId, 10);
            concurrencyUpdateManager.UpdateConcurrency();
            Assert.AreEqual(1, sessionProcessor.MaxConcurrentSessions);
            Assert.AreEqual(1, sessionProcessor.MaxConcurrentCallsPerSession);

            // ensure processor concurrency is adjusted up
            concurrencyUpdateManager.MessageProcessed();
            concurrencyUpdateManager.UpdateConcurrency();
            Assert.AreEqual(10, sessionProcessor.MaxConcurrentSessions);
            Assert.AreEqual(1, sessionProcessor.MaxConcurrentCallsPerSession);

            // ensure processor concurrency is adjusted down
            SetFunctionCurrentConcurrency(concurrencyManager, _functionId, 5);
            concurrencyUpdateManager.MessageProcessed();
            concurrencyUpdateManager.UpdateConcurrency();
            Assert.AreEqual(5, sessionProcessor.MaxConcurrentSessions);
            Assert.AreEqual(1, sessionProcessor.MaxConcurrentCallsPerSession);
        }
Ejemplo n.º 13
0
        public async Task PluginsSessionProcessor()
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
            {
                #region Snippet:End2EndPluginSessionProcessor
#if SNIPPET
                string connectionString = "<connection_string>";
                string queueName        = "<queue_name>";
                // since ServiceBusClient implements IAsyncDisposable we create it with "await using"
                await using var client = new ServiceBusClient(connectionString);
#else
                await using var client = CreateClient();
                string queueName = scope.QueueName;
#endif
                await using ServiceBusSender sender = client.CreatePluginSender(queueName, new List <Func <ServiceBusMessage, Task> >()
                {
                    message =>
                    {
                        message.Subject   = "Updated subject";
                        message.SessionId = "sessionId";
#if SNIPPET
                        Console.WriteLine("First send plugin executed!");
#endif
                        return(Task.CompletedTask);
                    },
                    message =>
                    {
#if SNIPPET
                        Console.WriteLine(message.Subject);   // prints "Updated subject"
                        Console.WriteLine(message.SessionId); // prints "sessionId"
                        Console.WriteLine("Second send plugin executed!");
#else
                        Assert.AreEqual("Updated subject", message.Subject);
                        Assert.AreEqual("sessionId", message.SessionId);
#endif
                        return(Task.CompletedTask);
                    },
                });

                await sender.SendMessageAsync(new ServiceBusMessage(Encoding.UTF8.GetBytes("First")));

#if !SNIPPET
                TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);
#endif
                await using ServiceBusSessionProcessor processor = client.CreatePluginSessionProcessor(queueName, new List <Func <ServiceBusReceivedMessage, Task> >()
                {
                    message =>
                    {
                        var rawMessage = message.GetRawAmqpMessage();
                        rawMessage.Properties.Subject = "Received subject";
#if SNIPPET
                        Console.WriteLine("First receive plugin executed!");
#endif
                        return(Task.CompletedTask);
                    },
                    message =>
                    {
#if SNIPPET
                        Console.WriteLine(message.Subject); // prints "Received subject"
#else
                        Assert.AreEqual("Received subject", message.Subject);
#endif
                        var rawMessage = message.GetRawAmqpMessage();
                        rawMessage.Properties.Subject = "Last subject";
#if SNIPPET
                        Console.WriteLine("Second receive plugin executed!");
#endif
                        return(Task.CompletedTask);
                    },
                });

                processor.ProcessMessageAsync += args =>
                {
#if SNIPPET
                    Console.WriteLine(args.Message.Subject);
#else
                    Assert.AreEqual("Last subject", args.Message.Subject);
                    tcs.TrySetResult(true);
#endif
                    return(Task.CompletedTask);
                };

                processor.ProcessErrorAsync += args =>
                {
#if SNIPPET
                    Console.WriteLine(args.Exception);
#endif
                    return(Task.CompletedTask);
                };

                await processor.StartProcessingAsync();

#if SNIPPET
                Console.ReadKey();
#else
                await tcs.Task;
#endif
                #endregion
            };
        }
Ejemplo n.º 14
0
        public async Task ProcessSessionMessages()
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
            {
                #region Snippet:ServiceBusProcessSessionMessages
#if SNIPPET
                string connectionString = "<connection_string>";
                string queueName        = "<queue_name>";
                // since ServiceBusClient implements IAsyncDisposable we create it with "await using"
                await using var client = new ServiceBusClient(connectionString);
#else
                string connectionString = TestEnvironment.ServiceBusConnectionString;
                string queueName        = scope.QueueName;
                await using var client = CreateClient();
#endif

                // create the sender
                ServiceBusSender sender = client.CreateSender(queueName);

                // create a message batch that we can send
                ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();

                messageBatch.TryAddMessage(
                    new ServiceBusMessage("First")
                {
                    SessionId = "Session1"
                });
                messageBatch.TryAddMessage(
                    new ServiceBusMessage("Second")
                {
                    SessionId = "Session2"
                });

                // send the message batch
                await sender.SendMessagesAsync(messageBatch);

                #region Snippet:ServiceBusConfigureSessionProcessor
                // create the options to use for configuring the processor
                var options = new ServiceBusSessionProcessorOptions
                {
                    // By default after the message handler returns, the processor will complete the message
                    // If I want more fine-grained control over settlement, I can set this to false.
                    AutoCompleteMessages = false,

                    // I can also allow for processing multiple sessions
                    MaxConcurrentSessions = 5,

                    // By default or when AutoCompleteMessages is set to true, the processor will complete the message after executing the message handler
                    // Set AutoCompleteMessages to false to [settle messages](https://docs.microsoft.com/en-us/azure/service-bus-messaging/message-transfers-locks-settlement#peeklock) on your own.
                    // In both cases, if the message handler throws an exception without settling the message, the processor will abandon the message.
                    MaxConcurrentCallsPerSession = 2,

                    // Processing can be optionally limited to a subset of session Ids.
                    SessionIds = { "my-session", "your-session" },
                };

                // create a session processor that we can use to process the messages
                await using ServiceBusSessionProcessor processor = client.CreateSessionProcessor(queueName, options);

                // configure the message and error handler to use
                processor.ProcessMessageAsync += MessageHandler;
                processor.ProcessErrorAsync   += ErrorHandler;

                async Task MessageHandler(ProcessSessionMessageEventArgs args)
                {
                    var body = args.Message.Body.ToString();

                    // we can evaluate application logic and use that to determine how to settle the message.
                    await args.CompleteMessageAsync(args.Message);

                    // we can also set arbitrary session state using this receiver
                    // the state is specific to the session, and not any particular message
                    await args.SetSessionStateAsync(new BinaryData("some state"));
                }

                Task ErrorHandler(ProcessErrorEventArgs args)
                {
                    // the error source tells me at what point in the processing an error occurred
                    Console.WriteLine(args.ErrorSource);
                    // the fully qualified namespace is available
                    Console.WriteLine(args.FullyQualifiedNamespace);
                    // as well as the entity path
                    Console.WriteLine(args.EntityPath);
                    Console.WriteLine(args.Exception.ToString());
                    return(Task.CompletedTask);
                }

                // start processing
                await processor.StartProcessingAsync();

                // since the processing happens in the background, we add a Conole.ReadKey to allow the processing to continue until a key is pressed.
                Console.ReadKey();
                #endregion
                #endregion
            }
        }
Ejemplo n.º 15
0
 public SessionMessageProcessor(ServiceBusSessionProcessor processor)
 {
     Processor = processor ?? throw new ArgumentNullException(nameof(processor));
 }
        public async Task SessionProcessorActivities()
        {
            ClientDiagnosticListener.ProducedLink[] messageActivities = null;
            int  messageProcessedCt = 0;
            bool callbackExecuted   = false;

            _listener = new ClientDiagnosticListener(
                EntityScopeFactory.DiagnosticNamespace,
                scopeStartCallback: scope =>
            {
                if (scope.Name == DiagnosticProperty.ProcessSessionMessageActivityName)
                {
                    Assert.IsNotNull(messageActivities);
                    Assert.AreEqual(
                        messageActivities[messageProcessedCt],
                        scope.Links.Single());
                    callbackExecuted = true;
                }
            });
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
            {
                var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);
                ServiceBusSender sender = client.CreateSender(scope.QueueName);
                var messageCt           = 2;
                var msgs = ServiceBusTestUtilities.GetMessages(messageCt, "sessionId");
                await sender.SendMessagesAsync(msgs);

                Activity[] sendActivities = AssertSendActivities(false, sender, msgs);
                messageActivities = sendActivities.Select(a => new ClientDiagnosticListener.ProducedLink(a.ParentId, a.TraceStateString)).ToArray();

                ServiceBusSessionProcessor processor = client.CreateSessionProcessor(scope.QueueName,
                                                                                     new ServiceBusSessionProcessorOptions
                {
                    AutoCompleteMessages  = false,
                    SessionIdleTimeout    = TimeSpan.FromSeconds(10),
                    MaxConcurrentSessions = 1
                });
                TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool>();
                processor.ProcessMessageAsync += args =>
                {
                    if (++messageProcessedCt == messageCt)
                    {
                        tcs.SetResult(true);
                    }
                    return(Task.CompletedTask);
                };
                processor.ProcessErrorAsync += ServiceBusTestUtilities.ExceptionHandler;
                await processor.StartProcessingAsync();

                await tcs.Task;
                await processor.StopProcessingAsync();

                for (int i = 0; i < messageCt; i++)
                {
                    _listener.AssertAndRemoveScope(DiagnosticProperty.ReceiveActivityName);
                    var processScope = _listener.AssertAndRemoveScope(DiagnosticProperty.ProcessSessionMessageActivityName);
                    AssertCommonTags(processScope.Activity, processor.EntityPath, processor.FullyQualifiedNamespace);
                }
                Assert.IsTrue(callbackExecuted);
            }
        }
        public async Task ProcessEventConsumesAllMessages(int numThreads, bool autoComplete)
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(
                             enablePartitioning: false,
                             enableSession: true))
            {
                await using var client = GetClient();
                ServiceBusSender sender = client.GetSender(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);
                }

                int messageCt = 0;

                TaskCompletionSource <bool> taskCompletionSource = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);
                var options = new ServiceBusProcessorOptions
                {
                    MaxConcurrentCalls = numThreads,
                    AutoComplete       = autoComplete
                };

                ServiceBusSessionProcessor processor = GetNoRetryClient().GetSessionProcessor(scope.QueueName, options);

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

                async Task ProcessMessage(ProcessSessionMessageEventArgs args)
                {
                    try
                    {
                        var message = args.Message;
                        if (!autoComplete)
                        {
                            await args.CompleteAsync(message);
                        }
                        sessions.TryRemove(message.SessionId, out bool _);
                        Assert.AreEqual(message.SessionId, args.SessionId);
                        Assert.IsNotNull(args.SessionLockedUntil);
                    }
                    finally
                    {
                        var ct = Interlocked.Increment(ref messageCt);
                        if (ct == numThreads)
                        {
                            taskCompletionSource.SetResult(true);
                        }
                    }
                }

                await taskCompletionSource.Task;
                await processor.StopProcessingAsync();

                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
                // only do this assertion when we complete the message ourselves,
                // otherwise the message completion may have been cancelled if it didn't finish
                // before calling StopProcessingAsync.


                if (!autoComplete)
                {
                    Assert.That(async() =>
                                await GetNoRetryClient().GetSessionReceiverAsync(scope.QueueName),
                                Throws.Exception);
                }
            }
        }
Ejemplo n.º 18
0
        public async Task ProcessSessionMessages()
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
            {
                string connectionString = TestEnvironment.ServiceBusConnectionString;
                string queueName        = scope.QueueName;
                await using var client = GetClient();

                #region Snippet:ServiceBusProcessSessionMessages
                //@@ string connectionString = "<connection_string>";
                //@@ string queueName = "<queue_name>";
                // since ServiceBusClient implements IAsyncDisposable we create it with "await using"
                //@@ await using var client = new ServiceBusClient(connectionString);

                // create the sender
                ServiceBusSender sender = client.CreateSender(queueName);

                // create a message batch that we can send
                ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();

                messageBatch.TryAddMessage(
                    new ServiceBusMessage(Encoding.UTF8.GetBytes("First"))
                {
                    SessionId = "Session1"
                });
                messageBatch.TryAddMessage(
                    new ServiceBusMessage(Encoding.UTF8.GetBytes("Second"))
                {
                    SessionId = "Session2"
                });

                // send the message batch
                await sender.SendMessagesAsync(messageBatch);

                // get the options to use for configuring the processor
                var options = new ServiceBusSessionProcessorOptions
                {
                    // By default after the message handler returns, the processor will complete the message
                    // If I want more fine-grained control over settlement, I can set this to false.
                    AutoCompleteMessages = false,

                    // I can also allow for processing multiple sessions
                    MaxConcurrentSessions = 5,

                    // By default, there will be a single concurrent call per session. I can
                    // increase that here to enable parallel processing within each session.
                    MaxConcurrentCallsPerSession = 2
                };

                // create a session processor that we can use to process the messages
                ServiceBusSessionProcessor processor = client.CreateSessionProcessor(queueName, options);

                // since the message handler will run in a background thread, in order to prevent
                // this sample from terminating immediately, we can use a task completion source that
                // we complete from within the message handler.
                TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);
                int processedMessageCount       = 0;
                processor.ProcessMessageAsync += MessageHandler;
                processor.ProcessErrorAsync   += ErrorHandler;

                async Task MessageHandler(ProcessSessionMessageEventArgs args)
                {
                    var body = args.Message.Body.ToString();

                    // we can evaluate application logic and use that to determine how to settle the message.
                    await args.CompleteMessageAsync(args.Message);

                    // we can also set arbitrary session state using this receiver
                    // the state is specific to the session, and not any particular message
                    await args.SetSessionStateAsync(new BinaryData("some state"));

                    // Once we've received the last message, complete the
                    // task completion source.
                    if (Interlocked.Increment(ref processedMessageCount) == 2)
                    {
                        tcs.SetResult(true);
                    }
                }

                Task ErrorHandler(ProcessErrorEventArgs args)
                {
                    // the error source tells me at what point in the processing an error occurred
                    Console.WriteLine(args.ErrorSource);
                    // the fully qualified namespace is available
                    Console.WriteLine(args.FullyQualifiedNamespace);
                    // as well as the entity path
                    Console.WriteLine(args.EntityPath);
                    Console.WriteLine(args.Exception.ToString());
                    return(Task.CompletedTask);
                }

                await processor.StartProcessingAsync();

                // await our task completion source task so that the message handler will be invoked at least once.
                await tcs.Task;

                // stop processing once the task completion source was completed.
                await processor.StopProcessingAsync();

                #endregion
            }
        }
Ejemplo n.º 19
0
 /// <summary>
 /// Initializes a new instance of <see cref="SessionMessageProcessor"/>.
 /// </summary>
 /// <param name="processor">The <see cref="ServiceBusSessionProcessor"/> to use for processing messages from Service Bus.</param>
 protected internal SessionMessageProcessor(ServiceBusSessionProcessor processor)
 {
     Processor = processor ?? throw new ArgumentNullException(nameof(processor));
 }