/// <summary>
        /// Convenience method for adding an item easily to the Transactional Outbox using Default implementations (e.g. GUID identifier).
        /// This method will create and commit the Transaction automatically, but may error if a running transaction
        /// is already in progress in which case the custom extension of the Transaction should be used directly instead.
        /// </summary>
        /// <typeparam name="TPayload"></typeparam>
        /// <param name="sqlConnection"></param>
        /// <param name="publishTarget"></param>
        /// <param name="payload"></param>
        /// <param name="fifoGroupingIdentifier"></param>
        /// <returns></returns>
        public static async Task <ISqlTransactionalOutboxItem <Guid> > AddTransactionalOutboxPendingItemAsync <TPayload>(
            this SqlConnection sqlConnection,
            string publishTarget,
            TPayload payload,
            string fifoGroupingIdentifier = null
            )
        {
            sqlConnection.AssertSqlConnectionIsValid();
            await using var outboxTransaction = (SqlTransaction)(await sqlConnection.BeginTransactionAsync().ConfigureAwait(false));
            try
            {
                var results = await outboxTransaction
                              .AddTransactionalOutboxPendingItemAsync(publishTarget, payload, fifoGroupingIdentifier)
                              .ConfigureAwait(false);

                await outboxTransaction.CommitAsync().ConfigureAwait(false);

                return(results);
            }
            catch (Exception)
            {
                await outboxTransaction.RollbackAsync().ConfigureAwait(false);

                throw;
            }
        }
        /// <summary>
        /// Convenience method for adding an item easily to the Transactional Outbox using Default implementations (e.g. GUID identifier).
        /// This method will create and commit the Transaction automatically, but may error if a running transaction
        /// is already in progress in which case the custom extension of the Transaction should be used directly instead.
        /// </summary>
        /// <typeparam name="TPayload"></typeparam>
        /// <param name="sqlConnection"></param>
        /// <param name="outboxInsertionItems"></param>
        /// <returns></returns>
        public static async Task <List <ISqlTransactionalOutboxItem <Guid> > > AddTransactionalOutboxPendingItemListAsync <TPayload>(
            this SqlConnection sqlConnection,
            IEnumerable <ISqlTransactionalOutboxInsertionItem <TPayload> > outboxInsertionItems
            )
        {
            sqlConnection.AssertSqlConnectionIsValid();
            await using var outboxTransaction = (SqlTransaction)(await sqlConnection.BeginTransactionAsync().ConfigureAwait(false));

            try
            {
                var results = await outboxTransaction
                              .AddTransactionalOutboxPendingItemListAsync(outboxInsertionItems)
                              .ConfigureAwait(false);

                await outboxTransaction.CommitAsync().ConfigureAwait(false);

                return(results);
            }
            catch (Exception)
            {
                await outboxTransaction.RollbackAsync().ConfigureAwait(false);

                throw;
            }
        }
Esempio n. 3
0
        public static async Task <ISqlTransactionalOutboxProcessingResults <Guid> > ProcessPendingOutboxItemsAsync(
            this SqlConnection sqlConnection,
            ISqlTransactionalOutboxPublisher <Guid> outboxPublisher,
            OutboxProcessingOptions processingOptions,
            bool throwExceptionOnFailure = false
            )
        {
            sqlConnection.AssertSqlConnectionIsValid();
            outboxPublisher.AssertNotNull(nameof(outboxPublisher));
            processingOptions.AssertNotNull(nameof(processingOptions));

            await using var outboxTransaction = (SqlTransaction)(await sqlConnection.BeginTransactionAsync().ConfigureAwait(false));
            try
            {
                var results = await outboxTransaction
                              .ProcessPendingOutboxItemsAsync(
                    outboxPublisher : outboxPublisher,
                    processingOptions : processingOptions,
                    throwExceptionOnFailure : throwExceptionOnFailure
                    )
                              .ConfigureAwait(false);

                await outboxTransaction.CommitAsync().ConfigureAwait(false);

                return(results);
            }
            catch (Exception)
            {
                await outboxTransaction.RollbackAsync().ConfigureAwait(false);

                throw;
            }
        }
        public static async Task <ISqlTransactionalOutboxProcessingResults <Guid> > ProcessPendingOutboxItemsAsync(
            this SqlConnection sqlConnection,
            ISqlTransactionalOutboxPublisher <Guid> outboxPublisher,
            OutboxProcessingOptions processingOptions,
            bool throwExceptionOnFailure = false
            )
        {
            sqlConnection.AssertSqlConnectionIsValid();
            outboxPublisher.AssertNotNull(nameof(outboxPublisher));
            processingOptions.AssertNotNull(nameof(processingOptions));

            await using var outboxTransaction = (SqlTransaction)(await sqlConnection.BeginTransactionAsync().ConfigureAwait(false));
            try
            {
                var results = await outboxTransaction
                              .ProcessPendingOutboxItemsAsync(
                    outboxPublisher : outboxPublisher,
                    processingOptions : processingOptions,
                    throwExceptionOnFailure : throwExceptionOnFailure
                    )
                              .ConfigureAwait(false);

                await outboxTransaction.CommitAsync().ConfigureAwait(false);

                return(results);
            }
            catch (Exception exc)
            {
                //FIRST Rollback any pending changes...
                await outboxTransaction.RollbackAsync().ConfigureAwait(false);

                try
                {
                    //THEN Attempt any Mitigating Actions for the Issue...
                    //IF WE have issues retrieving the new items from the DB then we attempt to increment the
                    //  Publish Attempts in case there is an issue with the entry that is causing failures, so
                    //  that any potential problematic items will eventually be failed out and skipped.
                    await sqlConnection.IncrementPublishAttemptsForAllPendingItemsAsync(outboxPublisher).ConfigureAwait(false);
                }
                catch (Exception mitigationExc)
                {
                    throw new AggregateException(new[] { exc, mitigationExc });
                }

                //FINALLY Re-throw to ensure we don't black hole the issue...
                throw;
            }
        }
        /// <summary>
        /// Execute the cleanup (e.g. Purge) of Historical data from the Outbox for the specified timespan
        /// of how much time to keep (e.g. last 30 days, last 90 days, etc.).
        /// This method will create and commit the Transaction automatically, but may error if a running transaction
        /// is already in progress in which case the custom extension of the Transaction should be used directly instead.
        /// </summary>
        /// <param name="sqlConnection"></param>
        /// <param name="historyTimeToKeepTimeSpan"></param>
        /// <returns></returns>
        public static async Task CleanupHistoricalOutboxItemsAsync(
            this SqlConnection sqlConnection,
            TimeSpan historyTimeToKeepTimeSpan
            )
        {
            sqlConnection.AssertSqlConnectionIsValid();
            await using var outboxTransaction = (SqlTransaction)(await sqlConnection.BeginTransactionAsync().ConfigureAwait(false));

            try
            {
                await outboxTransaction
                .CleanupHistoricalOutboxItemsAsync(historyTimeToKeepTimeSpan)
                .ConfigureAwait(false);

                await outboxTransaction.CommitAsync().ConfigureAwait(false);
            }
            catch (Exception)
            {
                await outboxTransaction.RollbackAsync().ConfigureAwait(false);

                throw;
            }
        }