Esempio n. 1
0
        public async Task TestAzureServiceBusTransactionalOutboxWithJsonPayload()
        {
            //*****************************************************************************************
            //* STEP 1 - Prepare the Test Payload Item to be Published
            //*****************************************************************************************
            var testPayload = new
            {
                PublishTarget  = TestConfiguration.AzureServiceBusTopic,
                To             = "CajunCoding",
                FifoGroupingId = nameof(TestAzureServiceBusDirectPublishingAndReceiving),
                ContentType    = MessageContentTypes.PlainText,
                Body           = $"Testing publishing of Json Payload with PlainText Body for [{nameof(TestAzureServiceBusTransactionalOutboxWithJsonPayload)}]!",
                Headers        = new
                {
                    IntegrationTestName = nameof(TestAzureServiceBusDirectPublishingAndReceiving),
                    IntegrationTestExecutionDateTime = DateTimeOffset.UtcNow
                }
            };

            var jsonText = JsonConvert.SerializeObject(testPayload);

            //*****************************************************************************************
            //* STEP 2 - Store the Dynamic Payload into the Outbox!
            //*****************************************************************************************
            var sqlConnection = await SqlConnectionHelper.CreateMicrosoftDataSqlConnectionAsync();

            await sqlConnection.TruncateTransactionalOutboxTableAsync();

            var outboxItem = await sqlConnection
                             .AddTransactionalOutboxPendingItemAsync(jsonText)
                             .ConfigureAwait(false);

            //*****************************************************************************************
            //* STEP 3 - Now Publish the Outbox payloads (processing all pending items)...
            //*****************************************************************************************
            await using var azureServiceBusPublisher = new DefaultAzureServiceBusOutboxPublisher(
                            TestConfiguration.AzureServiceBusConnectionString,
                            new AzureServiceBusPublishingOptions()
            {
                LogDebugCallback     = s => TestContext.WriteLine(s),
                ErrorHandlerCallback = e => TestContext.WriteLine(e.Message + e.InnerException?.Message)
            }
                            );

            var processedResults = await sqlConnection.ProcessPendingOutboxItemsAsync(azureServiceBusPublisher, new OutboxProcessingOptions()
            {
                FifoEnforcedPublishingEnabled = true,
                LogDebugCallback      = s => TestContext.WriteLine(s),
                ErrorHandlerCallback  = e => TestContext.WriteLine(e.Message + e.InnerException?.Message),
                MaxPublishingAttempts = 1,
                TimeSpanToLive        = TimeSpan.FromMinutes(5)
            });

            //*****************************************************************************************
            //* STEP 4 - Attempt to Retrieve/Receive the Message & Validate after Arrival!
            //*****************************************************************************************
            await AssertReceiptAndValidationOfThePublishedItem(outboxItem);
        }
Esempio n. 2
0
        public async Task TestAzureServiceBusDirectPublishingAndReceiving()
        {
            //*****************************************************************************************
            //* STEP 1 - Prepare the Test Outbox Item to be Published
            //*****************************************************************************************
            var testPayload = new
            {
                To             = "CajunCoding",
                FifoGroupingId = nameof(TestAzureServiceBusDirectPublishingAndReceiving),
                ContentType    = MessageContentTypes.PlainText,
                Body           = $"Testing publishing of Json Payload with PlainText Body for [{nameof(TestAzureServiceBusDirectPublishingAndReceiving)}]!",
                Headers        = new
                {
                    IntegrationTestName = nameof(TestAzureServiceBusDirectPublishingAndReceiving),
                    IntegrationTestExecutionDateTime = DateTimeOffset.UtcNow,
                }
            };

            var jsonPayload         = JsonConvert.SerializeObject(testPayload);
            var outboxItemFactory   = new DefaultOutboxItemFactory <string>();
            var uniqueIdGuidFactory = outboxItemFactory.UniqueIdentifierFactory;

            var outboxItem = outboxItemFactory.CreateExistingOutboxItem(
                uniqueIdentifier: uniqueIdGuidFactory.CreateUniqueIdentifier().ToString(),
                createdDateTimeUtc: DateTimeOffset.UtcNow,
                status: OutboxItemStatus.Pending.ToString(),
                fifoGroupingIdentifier: testPayload.FifoGroupingId,
                publishAttempts: 0,
                publishTarget: TestConfiguration.AzureServiceBusTopic,
                serializedPayload: jsonPayload
                );

            //*****************************************************************************************
            //* STEP 2 - Publish the receivedItem to Azure Service Bus!
            //*****************************************************************************************
            await using var azureServiceBusPublisher = new DefaultAzureServiceBusOutboxPublisher(
                            TestConfiguration.AzureServiceBusConnectionString,
                            new AzureServiceBusPublishingOptions()
            {
                LogDebugCallback     = s => TestContext.WriteLine(s),
                ErrorHandlerCallback = e => TestContext.WriteLine(e.Message + e.InnerException?.Message)
            }
                            );

            //Execute the publish to Azure...
            outboxItem.PublishAttempts++;
            await azureServiceBusPublisher.PublishOutboxItemAsync(outboxItem);

            //NOTE: Because we manually incremented the outbox item and mutated it (e.g. vs deep clone initialized from the DB)
            //      we now need to decrement it for Test Assertions to work as expected against the deep clone that will be received
            //      from the Azure Event Bus...
            outboxItem.PublishAttempts--;

            //*****************************************************************************************
            //* STEP 3 - Attempt to Retrieve/Receive the Message & Validate after Arrival!
            //*****************************************************************************************
            await AssertReceiptAndValidationOfThePublishedItem(outboxItem);
        }
        public static async Task Run([TimerTrigger("%TransactionalOutboxAgentCronSchedule%")] TimerInfo myTimer, ILogger log)
        {
            log.LogInformation($"Transactional Outbox Agent initiating process at: {DateTime.Now}");
            var configSettings = new SampleAppConfig();

            var azureServiceBusPublisher = new DefaultAzureServiceBusOutboxPublisher(
                configSettings.AzureServiceBusConnectionString,
                new AzureServiceBusPublishingOptions()
            {
                SenderApplicationName = $"{typeof(TransactionalOutboxAgentFunction).Assembly.GetName().Name}.{nameof(TransactionalOutboxAgentFunction)}",
                LogDebugCallback      = (s) => log.LogDebug(s),
                ErrorHandlerCallback  = (e) => log.LogError(e, "Unexpected Exception occurred while Processing the Transactional Outbox.")
            }
                );

            var outboxProcessingOptions = new OutboxProcessingOptions()
            {
                //ItemProcessingBatchSize = 200, //Only process the top X items to keep this function responsive!
                FifoEnforcedPublishingEnabled = true, //The Service Bus Topic is Session Enabled so we must processes it with FIFO Processing Enabled!
                LogDebugCallback      = (m) => log.LogDebug(m),
                ErrorHandlerCallback  = (e) => log.LogError(e, "Transactional Outbox Processing Exception"),
                MaxPublishingAttempts = configSettings.OutboxMaxPublishingRetryAttempts,
                TimeSpanToLive        = configSettings.OutboxMaxTimeToLiveTimeSpan
            };

            //************************************************************
            //*** Execute processing of the Transactional Outbox...
            //************************************************************
            await using var sqlConnection = new SqlConnection(configSettings.SqlConnectionString);
            await sqlConnection.OpenAsync().ConfigureAwait(false);

            await sqlConnection
            .ProcessPendingOutboxItemsAsync(azureServiceBusPublisher, outboxProcessingOptions)
            .ConfigureAwait(false);

            //************************************************************
            //*** Execute Cleanup of Historical Outbox Data...
            //************************************************************
            await sqlConnection
            .CleanupHistoricalOutboxItemsAsync(configSettings.OutboxHistoryToKeepTimeSpan)
            .ConfigureAwait(false);
        }
Esempio n. 4
0
        public OutboxProcessor(SampleAppConfig configSettings)
        {
            configSettings.AssertNotNull(nameof(configSettings));

            var errorHandlerCallback = new Action <Exception>((e) =>
            {
                Console.WriteLine($"  ERROR => {e.GetMessagesRecursively()}");
                OutboxHelpers.DefaultLogErrorCallback(e);
            });

            //We Need a Publisher to publish Outbox Items...
            //  NOTE: this is AsyncDisposable so we Keep a Reference for Disposal!
            OutboxPublisher = new DefaultAzureServiceBusOutboxPublisher(
                configSettings.AzureServiceBusConnectionString,
                new AzureServiceBusPublishingOptions()
            {
                SenderApplicationName = typeof(OutboxHelpers).Assembly.GetName().Name,
                LogDebugCallback      = OutboxHelpers.DefaultLogDebugCallback,
                ErrorHandlerCallback  = errorHandlerCallback
            }
                );

            //Finally We Need the Processing Agent to process the Outbox on a background (Async) thread...
            //  NOTE: this is AsyncDisposable so we Keep a Reference for Disposal!
            OutboxProcessingAgent = new AsyncThreadOutboxProcessingAgent(
                TimeSpan.FromSeconds(20),
                TimeSpan.FromDays(1),
                configSettings.SqlConnectionString,
                OutboxPublisher,
                //We Need Processing Options for the Agent...
                outboxProcessingOptions: new OutboxProcessingOptions()
            {
                //ItemProcessingBatchSize = 200, //Only process the top X items to keep this function responsive!
                FifoEnforcedPublishingEnabled = true,     //The Service Bus Topic is Session Enabled so we must processes it with FIFO Processing Enabled!
                LogDebugCallback      = OutboxHelpers.DefaultLogDebugCallback,
                ErrorHandlerCallback  = errorHandlerCallback,
                MaxPublishingAttempts = configSettings.OutboxMaxPublishingRetryAttempts,
                TimeSpanToLive        = configSettings.OutboxMaxTimeToLiveTimeSpan
            }
                );
        }