Exemplo n.º 1
0
        public async Task TransactionalSendViaCommitTest()
        {
            var connection = new ServiceBusConnection(ConnectionString);

            var intermediateQueue     = default(ServiceBusScope.QueueScope);
            var destination1          = default(ServiceBusScope.TopicScope);
            var destination2          = default(ServiceBusScope.QueueScope);
            var intermediateSender    = default(MessageSender);
            var intermediateReceiver  = default(MessageReceiver);
            var destination1Sender    = default(MessageSender);
            var destination1ViaSender = default(MessageSender);
            var destination2ViaSender = default(MessageSender);
            var destination1Receiver  = default(MessageReceiver);
            var destination2Receiver  = default(MessageReceiver);

            try
            {
                intermediateQueue = await ServiceBusScope.CreateQueueAsync(partitioned : true, sessionEnabled : false);

                destination1 = await ServiceBusScope.CreateTopicAsync(partitioned : true, sessionEnabled : false);

                destination2 = await ServiceBusScope.CreateQueueAsync(partitioned : false, sessionEnabled : false);

                var intermediateQueueName    = intermediateQueue.Name;
                var destination1Name         = destination1.TopicName;
                var destination1ReceiverName = EntityNameHelper.FormatSubscriptionPath(destination1.TopicName, destination1.SubscriptionName);
                var destination2Name         = destination2.Name;
                var destination2ReceiverName = destination2.Name;

                intermediateSender    = new MessageSender(connection, intermediateQueueName);
                intermediateReceiver  = new MessageReceiver(connection, intermediateQueueName);
                destination1Sender    = new MessageSender(connection, destination1Name);
                destination1ViaSender = new MessageSender(connection, destination1Name, intermediateQueueName);
                destination2ViaSender = new MessageSender(connection, destination2Name, intermediateQueueName);
                destination1Receiver  = new MessageReceiver(connection, destination1ReceiverName);
                destination2Receiver  = new MessageReceiver(connection, destination2ReceiverName);

                var body     = Guid.NewGuid().ToString("N");
                var message1 = new Message(body.GetBytes())
                {
                    MessageId = "1", PartitionKey = "pk1"
                };
                var message2 = new Message(body.GetBytes())
                {
                    MessageId = "2", PartitionKey = "pk2", ViaPartitionKey = "pk1"
                };
                var message3 = new Message(body.GetBytes())
                {
                    MessageId = "3", PartitionKey = "pk3", ViaPartitionKey = "pk1"
                };

                await intermediateSender.SendAsync(message1).ConfigureAwait(false);

                var receivedMessage = await intermediateReceiver.ReceiveAsync();

                Assert.NotNull(receivedMessage);
                Assert.Equal("pk1", receivedMessage.PartitionKey);

                // If the transaction succeeds, then all the operations occurred on the same partition.
                using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
                {
                    await intermediateReceiver.CompleteAsync(receivedMessage.SystemProperties.LockToken);

                    await destination1ViaSender.SendAsync(message2);

                    await destination2ViaSender.SendAsync(message3);

                    ts.Complete();
                }

                // Assert that first message indeed completed.
                receivedMessage = await intermediateReceiver.ReceiveAsync(ReceiveTimeout);

                Assert.Null(receivedMessage);

                // Assert that second message reached its destination.
                var receivedMessage1 = await destination1Receiver.ReceiveAsync();

                Assert.NotNull(receivedMessage1);
                Assert.Equal("pk2", receivedMessage1.PartitionKey);

                // Assert destination1 message actually used partitionKey in the destination entity.
                var destination1Message = new Message(body.GetBytes())
                {
                    PartitionKey = "pk2"
                };
                using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
                {
                    await destination1Receiver.CompleteAsync(receivedMessage1.SystemProperties.LockToken);

                    await destination1Sender.SendAsync(destination1Message);

                    ts.Complete();
                }

                // Assert that third message reached its destination.
                var receivedMessage2 = await destination2Receiver.ReceiveAsync();

                Assert.NotNull(receivedMessage2);
                Assert.Equal("pk3", receivedMessage2.PartitionKey);
                await destination2Receiver.CompleteAsync(receivedMessage2.SystemProperties.LockToken);

                // Cleanup
                receivedMessage1 = await destination1Receiver.ReceiveAsync();

                await destination1Receiver.CompleteAsync(receivedMessage1.SystemProperties.LockToken);
            }
            finally
            {
                // The cleanup methods will not throw and are safe to call outside of a try/catch.  They
                // also have no dependencies on execution order, so allowing them to run in parallel is fine.
                await Task.WhenAll(
                    SafeCloseAllAsync(intermediateSender, intermediateReceiver, destination1Sender, destination1ViaSender, destination2ViaSender, destination1Receiver, destination2Receiver),
                    intermediateQueue?.CleanupAsync(),
                    destination1?.CleanupAsync(),
                    destination2?.CleanupAsync());
            }
        }