async Task DispatchUsingReceiveTransaction(TransportTransaction transportTransaction, IEnumerable <UnicastTransportOperation> operations, CancellationToken cancellationToken)
        {
            transportTransaction.TryGet(SettingsKeys.TransportTransactionSqlConnectionKey, out SqlConnection sqlTransportConnection);
            transportTransaction.TryGet(SettingsKeys.TransportTransactionSqlTransactionKey, out SqlTransaction sqlTransportTransaction);
            transportTransaction.TryGet(out Transaction ambientTransaction);

            if (ambientTransaction != null)
            {
                if (sqlTransportConnection == null)
                {
                    using (var connection = await connectionFactory.OpenNewConnection(cancellationToken).ConfigureAwait(false))
                    {
                        await Dispatch(operations, connection, null, cancellationToken).ConfigureAwait(false);
                    }
                }
                else
                {
                    await Dispatch(operations, sqlTransportConnection, null, cancellationToken).ConfigureAwait(false);
                }
            }
            else
            {
                await Dispatch(operations, sqlTransportConnection, sqlTransportTransaction, cancellationToken).ConfigureAwait(false);
            }
        }
        static bool InReceiveWithNoTransactionMode(TransportTransaction transportTransaction)
        {
            SqlTransaction nativeTransaction;

            transportTransaction.TryGet(out nativeTransaction);

            Transaction ambientTransaction;

            transportTransaction.TryGet(out ambientTransaction);

            return(nativeTransaction == null && ambientTransaction == null);
        }
        public Task <CompletableSynchronizedStorageSession> TryAdapt(TransportTransaction transportTransaction, ContextBag context)
        {
            Transaction ambientTransaction;

            if (!transportTransaction.TryGet(out ambientTransaction))
            {
                return(EmptyResult);
            }
            var sessionFactoryImpl = sessionFactory as SessionFactoryImpl;

            if (sessionFactoryImpl == null)
            {
                throw new NotSupportedException("Overriding default implementation of ISessionFactory is not supported.");
            }
            CompletableSynchronizedStorageSession session = new NHibernateLazyAmbientTransactionSynchronizedStorageSession(
                connectionFactory: () => OpenConnection(sessionFactoryImpl, ambientTransaction),
                sessionFactory: conn =>
            {
                var sessionBuilder = sessionFactory.WithOptions();
                sessionBuilder.Connection(conn);
                return(sessionBuilder.OpenSession());
            });

            return(Task.FromResult(session));
        }
        static bool InReceiveWithNoTransactionMode(TransportTransaction transportTransaction)
        {
            transportTransaction.TryGet(SettingsKeys.TransportTransactionSqlTransactionKey, out SqlTransaction nativeTransaction);
            transportTransaction.TryGet(out Transaction ambientTransaction);

            return(nativeTransaction == null && ambientTransaction == null);
        }
        public Task Dispatch(TransportOperations outgoingMessages, TransportTransaction transaction, ContextBag context)
        {
            InMemoryTransaction inMemoryTransaction = null;

            if (transaction.TryGet(out inMemoryTransaction))
            {
            }

            foreach (var unicastTransportOperation in outgoingMessages.UnicastTransportOperations)
            {
                if (inMemoryTransaction != null && unicastTransportOperation.RequiredDispatchConsistency != DispatchConsistency.Isolated)
                {
                    var x = unicastTransportOperation;
                    inMemoryTransaction.Enlist(() => DispatchUnicastMessage(x));
                }
                else
                {
                    DispatchUnicastMessage(unicastTransportOperation);
                }
            }

            foreach (var multicastTransportOperation in outgoingMessages.MulticastTransportOperations)
            {
                if (inMemoryTransaction != null && multicastTransportOperation.RequiredDispatchConsistency != DispatchConsistency.Isolated)
                {
                    inMemoryTransaction.Enlist(() => DispatchMulticastMessage(multicastTransportOperation));
                }
                else
                {
                    DispatchMulticastMessage(multicastTransportOperation);
                }
            }

            return(Task.CompletedTask);
        }
예제 #6
0
            internal override async Task <StorageSession> TryAdaptTransportConnection(
                TransportTransaction transportTransaction,
                ContextBag context,
                IConnectionManager connectionManager,
                Func <DbConnection, DbTransaction, bool, StorageSession> storageSessionFactory,
                CancellationToken cancellationToken = default)
            {
                if (DoNotUseTransportConnection)
                {
                    return(null);
                }

                // SQL server transport in native TX mode
                if (transportTransaction.TryGet("System.Data.SqlClient.SqlConnection", out DbConnection existingSqlConnection) &&
                    transportTransaction.TryGet("System.Data.SqlClient.SqlTransaction", out DbTransaction existingSqlTransaction))
                {
                    return(storageSessionFactory(existingSqlConnection, existingSqlTransaction, false));
                }

                // Transport supports DTC and uses TxScope owned by the transport
                var scopeTx = Transaction.Current;

                if (transportTransaction.TryGet(out Transaction transportTx) &&
                    scopeTx != null &&
                    transportTx != scopeTx)
                {
                    throw new Exception("A TransactionScope has been opened in the current context overriding the one created by the transport. "
                                        + "This setup can result in inconsistent data because operations done via connections enlisted in the context scope won't be committed "
                                        + "atomically with the receive transaction. To manually control the TransactionScope in the pipeline switch the transport transaction mode "
                                        + $"to values lower than '{nameof(TransportTransactionMode.TransactionScope)}'.");
                }

                var ambientTransaction = transportTx ?? scopeTx;

                if (ambientTransaction == null)
                {
                    // Other modes handled by creating a new session.
                    return(null);
                }

                var connection = await connectionManager.OpenConnection(context.GetIncomingMessage(), cancellationToken).ConfigureAwait(false);

                connection.EnlistTransaction(ambientTransaction);

                return(storageSessionFactory(connection, null, true));
            }
예제 #7
0
        static bool TryGetReceiveContext(TransportTransaction transportTransaction, out ReceiveContext receiveContext)
        {
            if (transportTransaction == null)
            {
                receiveContext = null;
                return(false);
            }

            return(transportTransaction.TryGet(out receiveContext));
        }
예제 #8
0
        public Task <CompletableSynchronizedStorageSession> TryAdapt(TransportTransaction transportTransaction, ContextBag context)
        {
            IEventStoreConnection connection;

            if (!transportTransaction.TryGet(out connection))
            {
                throw new Exception("EventStore persistence can only be used with EventStore transport.");
            }
            return(Task.FromResult <CompletableSynchronizedStorageSession>(new EventStoreSynchronizedStorageSession(connection)));
        }
        public async Task <CompletableSynchronizedStorageSession> TryAdapt(TransportTransaction transportTransaction, ContextBag context)
        {
            Transaction ambientTransaction;

            if (transportTransaction.TryGet(out ambientTransaction))
            {
                NpgsqlConnection existingSqlConnection;
                //SQL server transport in ambient TX mode
                if (transportTransaction.TryGet(out existingSqlConnection))
                {
                    return(new StorageSession(existingSqlConnection, null));
                }
                //Other transport in ambient TX mode
                var connection = await NpgSqlHelpers.NewConnection(_connectionString);

                return(new StorageSession(connection, connection.BeginTransaction()));
            }
            return(null);
        }
        async Task DispatchIsolated(SortingResult sortedOperations, TransportTransaction transportTransaction, CancellationToken cancellationToken)
        {
            if (sortedOperations.IsolatedDispatch == null)
            {
                return;
            }

            transportTransaction.TryGet(SettingsKeys.IsUserProvidedTransactionKey, out bool userProvidedTransaction);

            if (userProvidedTransaction)
            {
                transportTransaction.TryGet(SettingsKeys.TransportTransactionSqlTransactionKey, out SqlTransaction sqlTransportTransaction);
                if (sqlTransportTransaction != null)
                {
                    await Dispatch(sortedOperations.IsolatedDispatch, sqlTransportTransaction.Connection, sqlTransportTransaction, cancellationToken).ConfigureAwait(false);

                    return;
                }

                transportTransaction.TryGet(SettingsKeys.TransportTransactionSqlConnectionKey, out SqlConnection sqlTransportConnection);
                if (sqlTransportConnection != null)
                {
                    await Dispatch(sortedOperations.IsolatedDispatch, sqlTransportConnection, null, cancellationToken).ConfigureAwait(false);

                    return;
                }

                throw new Exception($"Invalid {nameof(TransportTransaction)} state. Transaction provided by the user but contains no SqlTransaction or SqlConnection objects.");
            }

            using (var scope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled))
                using (var connection = await connectionFactory.OpenNewConnection(cancellationToken).ConfigureAwait(false))
                    using (var tx = connection.BeginTransaction())
                    {
                        await Dispatch(sortedOperations.IsolatedDispatch, connection, tx, cancellationToken).ConfigureAwait(false);

                        tx.Commit();
                        scope.Complete();
                    }
        }
예제 #11
0
        public Task <CompletableSynchronizedStorageSession> TryAdapt(TransportTransaction transportTransaction, ContextBag context)
        {
            Transaction ambientTransaction;

            if (transportTransaction.TryGet(out ambientTransaction))
            {
                var session = context.GetSession();
                CompletableSynchronizedStorageSession completableSynchronizedStorageSession = new MartenSynchronizedStorageSession(session, true);
                return(Task.FromResult(completableSynchronizedStorageSession));
            }

            return(EmptyResult);
        }
        async Task DispatchUsingReceiveTransaction(TransportTransaction transportTransaction, List <UnicastTransportOperation> operations)
        {
            SqlConnection  sqlTransportConnection;
            SqlTransaction sqlTransportTransaction;
            Transaction    ambientTransaction;

            transportTransaction.TryGet(out sqlTransportConnection);
            transportTransaction.TryGet(out sqlTransportTransaction);
            transportTransaction.TryGet(out ambientTransaction);

            if (ambientTransaction != null)
            {
                using (var connection = await connectionFactory.OpenNewConnection().ConfigureAwait(false))
                {
                    await Send(operations, connection, null).ConfigureAwait(false);
                }
            }
            else
            {
                await Send(operations, sqlTransportConnection, sqlTransportTransaction).ConfigureAwait(false);
            }
        }
        public Task <CompletableSynchronizedStorageSession> TryAdapt(TransportTransaction transportTransaction, ContextBag context)
        {
            // ReSharper disable once NotAccessedVariable - No way to just check for existence otherwise
            Transaction ambientTransaction;

            if (transportTransaction.TryGet(out ambientTransaction))
            {
                var session = context.GetAsyncSession();
                CompletableSynchronizedStorageSession completableSynchronizedStorageSession = new RavenDBSynchronizedStorageSession(session, true);
                return(Task.FromResult(completableSynchronizedStorageSession));
            }
            return(EmptyResult);
        }
        public async Task Dispatch(TransportOperations outgoingMessages, TransportTransaction transportTransaction, ContextBag context)
        {
            IEventStoreConnection c;

            if (transportTransaction.TryGet(out c))
            {
                await Dispatch(outgoingMessages, c).ConfigureAwait(false);
            }
            else
            {
                await Dispatch(outgoingMessages, sharedConnection).ConfigureAwait(false);
            }
        }
예제 #15
0
        public Task <CompletableSynchronizedStorageSession> TryAdapt(TransportTransaction transportTransaction, ContextBag context)
        {
            Transaction ambientTransaction;

            if (transportTransaction.TryGet(out ambientTransaction))
            {
                var transaction = new InMemoryTransaction();
                CompletableSynchronizedStorageSession session = new InMemorySynchronizedStorageSession(transaction);
                ambientTransaction.EnlistVolatile(new EnlistmentNotification(transaction), EnlistmentOptions.None);
                return(Task.FromResult(session));
            }
            return(EmptyTask);
        }
        public Task<CompletableSynchronizedStorageSession> TryAdapt(TransportTransaction transportTransaction, ContextBag context)
        {
            Transaction ambientTransaction;

            if (transportTransaction.TryGet(out ambientTransaction))
            {
                var transaction = new InMemoryTransaction();
                CompletableSynchronizedStorageSession session = new InMemorySynchronizedStorageSession(transaction);
                ambientTransaction.EnlistVolatile(new EnlistmentNotification(transaction), EnlistmentOptions.None);
                return Task.FromResult(session);
            }
            return EmptyTask;
        }
    public async Task <CompletableSynchronizedStorageSession> TryAdapt(TransportTransaction transportTransaction, ContextBag context)
    {
        SqlConnection  existingSqlConnection;
        SqlTransaction existingSqlTransaction;

        //SQL server transport in native TX mode
        if (transportTransaction.TryGet(out existingSqlConnection) &&
            transportTransaction.TryGet(out existingSqlTransaction))
        {
            return(new StorageSession(existingSqlConnection, existingSqlTransaction, false, infoCache));
        }

        // Transport supports DTC and uses TxScope owned by the transport
        Transaction transportTx;
        var         scopeTx = Transaction.Current;

        if (transportTransaction.TryGet(out transportTx) &&
            scopeTx != null &&
            transportTx != scopeTx)
        {
            throw new Exception("A TransactionScope has been opened in the current context overriding the one created by the transport. "
                                + "This setup can result in inconsistent data because operations done via connections enlisted in the context scope won't be committed "
                                + "atomically with the receive transaction. To manually control the TransactionScope in the pipeline switch the transport transaction mode "
                                + $"to values lower than '{nameof(TransportTransactionMode.TransactionScope)}'.");
        }
        var ambientTransaction = transportTx ?? scopeTx;

        if (ambientTransaction != null)
        {
            var connection = await connectionBuilder.OpenConnection().ConfigureAwait(false);

            connection.EnlistTransaction(ambientTransaction);
            return(new StorageSession(connection, null, true, infoCache));
        }

        //Other modes handled by creating a new session.
        return(null);
    }
예제 #18
0
 static bool TryGetNativeTransaction(TransportTransaction transportTransaction,
                                     out MessageQueueTransaction transaction)
 {
     return(transportTransaction.TryGet(out transaction));
 }
        public Task Dispatch(TransportOperations outgoingMessages, TransportTransaction transaction, CancellationToken cancellationToken = default)
        {
            // Assumption: we're not implementing batching as it will be done by ASB client
            transaction.TryGet <ServiceBusClient>(out var client);
            transaction.TryGet <string>("IncomingQueue.PartitionKey", out var partitionKey);
            transaction.TryGet <CommittableTransaction>(out var committableTransaction);

            var unicastTransportOperations   = outgoingMessages.UnicastTransportOperations;
            var multicastTransportOperations = outgoingMessages.MulticastTransportOperations;

            var tasks = new List <Task>(unicastTransportOperations.Count + multicastTransportOperations.Count);

            foreach (var transportOperation in unicastTransportOperations)
            {
                var destination = transportOperation.Destination;

                // Workaround for reply-to address set by ASB transport
                var index = transportOperation.Destination.IndexOf('@');

                if (index > 0)
                {
                    destination = destination.Substring(0, index);
                }

                var sender = messageSenderPool.GetMessageSender(destination, client);

                try
                {
                    var message = transportOperation.Message.ToAzureServiceBusMessage(transportOperation.Properties, partitionKey);

                    ApplyCustomizationToOutgoingNativeMessage(transportOperation, message, transaction);

                    var transactionToUse = transportOperation.RequiredDispatchConsistency == DispatchConsistency.Isolated ? null : committableTransaction;
                    using (var scope = transactionToUse.ToScope())
                    {
                        // Invoke sender and immediately return it back to the pool w/o awaiting for completion
                        tasks.Add(sender.SendMessageAsync(message, cancellationToken));
                        //committable tx will not be committed because this scope is not the owner
                        scope.Complete();
                    }
                }
                finally
                {
                    messageSenderPool.ReturnMessageSender(sender, client);
                }
            }

            foreach (var transportOperation in multicastTransportOperations)
            {
                var sender = messageSenderPool.GetMessageSender(topicName, client);

                try
                {
                    var message = transportOperation.Message.ToAzureServiceBusMessage(transportOperation.Properties, partitionKey);

                    ApplyCustomizationToOutgoingNativeMessage(transportOperation, message, transaction);

                    var transactionToUse = transportOperation.RequiredDispatchConsistency == DispatchConsistency.Isolated ? null : committableTransaction;
                    using (var scope = transactionToUse.ToScope())
                    {
                        // Invoke sender and immediately return it back to the pool w/o awaiting for completion
                        tasks.Add(sender.SendMessageAsync(message, cancellationToken));
                        //committable tx will not be committed because this scope is not the owner
                        scope.Complete();
                    }
                }
                finally
                {
                    messageSenderPool.ReturnMessageSender(sender, client);
                }
            }

            return(tasks.Count == 1 ? tasks[0] : Task.WhenAll(tasks));
        }
 static bool InReceiveOnlyTransportTransactionMode(TransportTransaction transportTransaction)
 {
     return(transportTransaction.TryGet(ProcessWithNativeTransaction.ReceiveOnlyTransactionMode, out bool _));
 }
        public Task Dispatch(TransportOperations outgoingMessages, TransportTransaction transaction, ContextBag context)
        {
            // Assumption: we're not implementing batching as it will be done by ASB client

            var receiverConnectionAndPathFound = transaction.TryGet <(ServiceBusConnection, string)>(out var receiverConnectionAndPath);
            var partitionKeyFound         = transaction.TryGet <string>("IncomingQueue.PartitionKey", out var partitionKey);
            var shouldSuppressTransaction = !(receiverConnectionAndPathFound && partitionKeyFound) && Transaction.Current != null;

            var unicastTransportOperations   = outgoingMessages.UnicastTransportOperations;
            var multicastTransportOperations = outgoingMessages.MulticastTransportOperations;

            var tasks = new List <Task>(unicastTransportOperations.Count + multicastTransportOperations.Count);

            foreach (var transportOperation in unicastTransportOperations)
            {
                var destination = transportOperation.Destination;

                // Workaround for reply-to address set by ASB transport
                var index = transportOperation.Destination.IndexOf('@');

                if (index > 0)
                {
                    destination = destination.Substring(0, index);
                }

                var receiverConnectionAndPathToUse = transportOperation.RequiredDispatchConsistency == DispatchConsistency.Isolated ? (null, null) : receiverConnectionAndPath;

                var sender = messageSenderPool.GetMessageSender(destination, receiverConnectionAndPathToUse);

                try
                {
                    var message = transportOperation.Message.ToAzureServiceBusMessage(transportOperation.DeliveryConstraints, partitionKey);

                    using (var scope = CreateTransactionScope(transportOperation.RequiredDispatchConsistency, shouldSuppressTransaction))
                    {
                        // Invoke sender and immediately return it back to the pool w/o awaiting for completion
                        tasks.Add(sender.SendAsync(message));
                        scope?.Complete();
                    }
                }
                finally
                {
                    messageSenderPool.ReturnMessageSender(sender);
                }
            }

            foreach (var transportOperation in multicastTransportOperations)
            {
                var receiverConnectionAndPathToUse = transportOperation.RequiredDispatchConsistency == DispatchConsistency.Isolated ? (null, null) : receiverConnectionAndPath;

                var sender = messageSenderPool.GetMessageSender(topicName, receiverConnectionAndPathToUse);

                try
                {
                    var message = transportOperation.Message.ToAzureServiceBusMessage(transportOperation.DeliveryConstraints, partitionKey);

                    using (var scope = CreateTransactionScope(transportOperation.RequiredDispatchConsistency, shouldSuppressTransaction))
                    {
                        // Invoke sender and immediately return it back to the pool w/o awaiting for completion
                        tasks.Add(sender.SendAsync(message));
                        scope?.Complete();
                    }
                }
                finally
                {
                    messageSenderPool.ReturnMessageSender(sender);
                }
            }

            return(tasks.Count == 1 ? tasks[0] : Task.WhenAll(tasks));
        }
 static bool TryGetNativeTransaction(TransportTransaction transportTransaction, out MessageQueueTransaction transaction)
 {
     return transportTransaction.TryGet(out transaction);
 }