Пример #1
0
        /// <summary>
        /// Sends the given <see cref="TransportMessage"/> to the queue with the specified globally addressable name
        /// </summary>
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            context.OnCommitted(async() =>
            {
                var queue             = GetQueue(destinationAddress);
                var messageId         = Guid.NewGuid().ToString();
                var popReceipt        = Guid.NewGuid().ToString();
                var timeToBeReceived  = GetTimeToBeReceivedOrNull(message);
                var cloudQueueMessage = Serialize(message, messageId, popReceipt);

                try
                {
                    var options = new QueueRequestOptions {
                        RetryPolicy = new ExponentialRetry()
                    };
                    var operationContext = new OperationContext();

                    await queue.AddMessageAsync(cloudQueueMessage, timeToBeReceived, null, options, operationContext);
                }
                catch (Exception exception)
                {
                    throw new RebusApplicationException(string.Format("Could not send message with ID {0} to '{1}'", cloudQueueMessage.Id, destinationAddress), exception);
                }
            });
        }
        /// <summary>
        /// Sends the given <see cref="TransportMessage"/> to the queue with the specified globally addressable name
        /// </summary>
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            context.OnCommitted(async() =>
            {
                var headers                    = message.Headers.Clone();
                var queue                      = GetQueue(destinationAddress);
                var messageId                  = Guid.NewGuid().ToString();
                var popReceipt                 = Guid.NewGuid().ToString();
                var timeToBeReceivedOrNull     = GetTimeToBeReceivedOrNull(headers);
                var queueVisibilityDelayOrNull = GetQueueVisibilityDelayOrNull(headers);
                var cloudQueueMessage          = Serialize(messageId, popReceipt, headers, message.Body);

                try
                {
                    var options = new QueueRequestOptions {
                        RetryPolicy = new ExponentialRetry()
                    };
                    var operationContext = new OperationContext();

                    await queue.AddMessageAsync(cloudQueueMessage, timeToBeReceivedOrNull, queueVisibilityDelayOrNull, options, operationContext);
                }
                catch (Exception exception)
                {
                    throw new RebusApplicationException(exception, $"Could not send message with ID {cloudQueueMessage.Id} to '{destinationAddress}'");
                }
            });
        }
Пример #3
0
        ConcurrentDictionary <string, ConcurrentQueue <TransportMessage> > GetOutgoingMessages(ITransactionContext context)
        {
            return(context.GetOrAdd(OutgoingMessagesKey, () =>
            {
                var destinations = new ConcurrentDictionary <string, ConcurrentQueue <TransportMessage> >();

                context.OnCommitted(async() =>
                {
                    // send outgoing messages
                    foreach (var destinationAndMessages in destinations)
                    {
                        var destinationAddress = destinationAndMessages.Key;
                        var messages = destinationAndMessages.Value;

                        var sendTasks = messages
                                        .Select(async message =>
                        {
                            await GetRetrier().Execute(async() =>
                            {
                                using (var brokeredMessageToSend = CreateBrokeredMessage(message))
                                {
                                    await GetQueueClient(destinationAddress).SendAsync(brokeredMessageToSend);
                                }
                            });
                        })
                                        .ToArray();

                        await Task.WhenAll(sendTasks);
                    }
                });

                return destinations;
            }));
        }
        /// <inheritdoc />
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            if (destinationAddress == null)
            {
                throw new ArgumentNullException(nameof(destinationAddress));
            }
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var outgoingMessages = context.GetOrAdd(OutgoingMessagesItemsKey, () =>
            {
                var sendMessageBatchRequestEntries = new ConcurrentQueue <OutgoingMessage>();

                context.OnCommitted(() => SendOutgoingMessages(sendMessageBatchRequestEntries, context));

                return(sendMessageBatchRequestEntries);
            });

            outgoingMessages.Enqueue(new OutgoingMessage(destinationAddress, message));
        }
Пример #5
0
        /// <inheritdoc />
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            if (destinationAddress == null)
            {
                throw new ArgumentNullException(nameof(destinationAddress));
            }
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var outgoingMessages = context.GetOrAdd(OutgoingMessagesItemsKey, () =>
            {
                var messagesToSend = new ConcurrentQueue <OutgoingMessage>();

                context.OnCommitted(async ctx => await SendOutgoingMessages(messagesToSend));

                return(messagesToSend);
            });

            outgoingMessages.Enqueue(new OutgoingMessage(GetActualDestinationAddress(destinationAddress, message), message));
        }
        /// <summary>
        /// Responsible for releasing the lease on message failure and removing the message on transaction commit
        /// </summary>
        /// <param name="context">Transaction context of the message processing</param>
        /// <param name="messageId">Identifier of the message currently being processed</param>
        private void ApplyTransactionSemantics(ITransactionContext context, long messageId)
        {
            context.OnAborted(
                async ctx =>
            {
                try
                {
                    await ClearProcessing(messageId).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    _log.Error(ex, "While Resetting Lease");
                }
            }
                );

            context.OnCommitted(
                async ctx =>
            {
                try
                {
                    await DeleteMessage(messageId).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    _log.Error(ex, "While Deleting Message");
                }
            }
                );
        }
Пример #7
0
        public Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            // if there is a IOutboxContext associated with this Send(), batch message and store them on commit
            var ctx = context.GetOrNull <IOutboxContext>(_outboxContextItemsKey);

            if (ctx != null)
            {
                var outgoingMessages = context.GetOrAdd(_outgoingMessagesItemsKey, () =>
                {
                    var messages = new ConcurrentQueue <OutboxMessage>();

                    context.OnCommitted(tc => ctx.SendAsync(messages));

                    return(messages);
                });

                message.Headers.Add(_outboxRecepientHeader, destinationAddress);

                outgoingMessages.Enqueue(new OutboxMessage
                {
                    Body    = message.Body,
                    Headers = message.Headers
                });

                return(Task.CompletedTask);
            }

            // otherwise, there isn't an associated Context, thus just write directly to transport
            return(_inner.Send(destinationAddress, message, context));
        }
        /// <summary>
        /// Sends the given <see cref="TransportMessage"/> to the queue with the specified globally addressable name
        /// </summary>
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            context.OnCommitted(async () =>
            {
                var headers = message.Headers.Clone();
                var queue = GetQueue(destinationAddress);
                var messageId = Guid.NewGuid().ToString();
                var popReceipt = Guid.NewGuid().ToString();
                var timeToBeReceivedOrNull = GetTimeToBeReceivedOrNull(headers);
                var queueVisibilityDelayOrNull = GetQueueVisibilityDelayOrNull(headers);
                var cloudQueueMessage = Serialize(messageId, popReceipt, headers, message.Body);

                try
                {
                    var options = new QueueRequestOptions {RetryPolicy = new ExponentialRetry()};
                    var operationContext = new OperationContext();

                    await queue.AddMessageAsync(cloudQueueMessage, timeToBeReceivedOrNull, queueVisibilityDelayOrNull, options, operationContext);
                }
                catch (Exception exception)
                {
                    throw new RebusApplicationException(exception, $"Could not send message with ID {cloudQueueMessage.Id} to '{destinationAddress}'");
                }
            });
        }
Пример #9
0
        ConcurrentQueue <OutgoingMessage> GetOutgoingMessages(ITransactionContext context)
        {
            return(context.GetOrAdd(OutgoingMessagesKey, () =>
            {
                var messagesToSend = new ConcurrentQueue <OutgoingMessage>();

                context.OnCommitted(async() =>
                {
                    var messagesByDestinationQueue = messagesToSend.GroupBy(m => m.DestinationAddress);

                    await Task.WhenAll(messagesByDestinationQueue.Select(async group =>
                    {
                        var destinationQueue = group.Key;
                        var messages = group;

                        if (destinationQueue.StartsWith(MagicSubscriptionPrefix))
                        {
                            var topicName = _azureServiceBusNameHelper.ReplaceInvalidCharacters(destinationQueue.Substring(MagicSubscriptionPrefix.Length));

                            foreach (var batch in messages.Batch(DefaultOutgoingBatchSize))
                            {
                                var list = batch.Select(GetMessage).ToList();

                                try
                                {
                                    await GetTopicClient(topicName).SendAsync(list).ConfigureAwait(false);
                                }
                                catch (MessagingEntityNotFoundException)
                                {
                                    // if the topic does not exist, it's allright
                                }
                                catch (Exception exception)
                                {
                                    throw new RebusApplicationException(exception, $"Could not publish to topic '{topicName}'");
                                }
                            }
                        }
                        else
                        {
                            foreach (var batch in messages.Batch(DefaultOutgoingBatchSize))
                            {
                                var list = batch.Select(GetMessage).ToList();

                                try
                                {
                                    await GetMessageSender(destinationQueue).SendAsync(list).ConfigureAwait(false);
                                }
                                catch (Exception exception)
                                {
                                    throw new RebusApplicationException(exception, $"Could not send to queue '{destinationQueue}'");
                                }
                            }
                        }
                    })).ConfigureAwait(false);
                });

                return messagesToSend;
            }));
        }
        async Task <IDbConnection> GetConnection(ITransactionContext context)
        {
            // Get the connection and set it up to be disposed or committed in the transaction context. MySQL cannot
            // share connections, so we do not store it in the shared context items, but create a new one each time.
            var connection = await _connectionProvider.GetConnectionAsync().ConfigureAwait(false);

            context.OnCommitted(async ctx => await connection.CompleteAsync().ConfigureAwait(false));
            context.OnDisposed(ctx => connection.Dispose());
            return(connection);
        }
            public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
            {
                var networkToUse = context.GetOrAdd(CurrentNetworkConnectionKey, () => _network);

                if (!networkToUse.HasQueue(destinationAddress))
                {
                    throw new ArgumentException($"Destination queue address '{destinationAddress}' does not exist!");
                }

                context.OnCommitted(async _ => networkToUse.Deliver(destinationAddress, message.ToInMemTransportMessage()));
            }
Пример #12
0
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            var outgoingMessages = context.GetOrAdd(OutgoingMessagesItemsKey, () =>
            {
                context.OnCommitted(async () => SendOutgoingMessages(context));

                return new ConcurrentQueue<OutgoingMessage>();
            });

            outgoingMessages.Enqueue(new OutgoingMessage(destinationAddress, message));
        }
Пример #13
0
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            var outgoingMessages = context.GetOrAdd(OutgoingMessagesItemsKey, () =>
            {
                context.OnCommitted(async() => SendOutgoingMessages(context));

                return(new ConcurrentQueue <OutgoingMessage>());
            });

            outgoingMessages.Enqueue(new OutgoingMessage(destinationAddress, message));
        }
Пример #14
0
        /// <summary>
        /// Sends the given transport message to the specified destination address using MSMQ. Will use the existing <see cref="MessageQueueTransaction"/> stashed
        /// under the <see cref="CurrentTransactionKey"/> key in the given <paramref name="context"/>, or else it will create one and add it.
        /// </summary>
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            if (destinationAddress == null)
            {
                throw new ArgumentNullException(nameof(destinationAddress));
            }
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var logicalMessage = CreateMsmqMessage(message);

            var messageQueueTransaction = context.GetOrAdd(CurrentTransactionKey, () =>
            {
                var messageQueueTransaction1 = new MessageQueueTransaction();
                messageQueueTransaction1.Begin();

                context.OnCommitted(async() => messageQueueTransaction1.Commit());

                return(messageQueueTransaction1);
            });

            var sendQueues = context.GetOrAdd(CurrentOutgoingQueuesKey, () =>
            {
                var messageQueues = new ConcurrentDictionary <string, MessageQueue>(StringComparer.InvariantCultureIgnoreCase);

                context.OnDisposed(() =>
                {
                    foreach (var messageQueue in messageQueues.Values)
                    {
                        messageQueue.Dispose();
                    }
                });

                return(messageQueues);
            });

            var path = MsmqUtil.GetFullPath(destinationAddress);

            var sendQueue = sendQueues.GetOrAdd(path, _ =>
            {
                var messageQueue = new MessageQueue(path, QueueAccessMode.Send);

                return(messageQueue);
            });

            sendQueue.Send(logicalMessage, messageQueueTransaction);
        }
Пример #15
0
        /// <summary>
        /// Delivers the given message to the queue identitied by the given <paramref name="destinationAddress"/>
        /// </summary>
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            if (destinationAddress == null) throw new ArgumentNullException("destinationAddress");
            if (message == null) throw new ArgumentNullException("message");
            if (context == null) throw new ArgumentNullException("context");

            if (!_network.HasQueue(destinationAddress))
            {
                throw new ArgumentException(string.Format("Destination queue address '{0}' does not exist!", destinationAddress));
            }

            context.OnCommitted(async () => _network.Deliver(destinationAddress, message.ToInMemTransportMessage()));
        }
Пример #16
0
        /// <inheritdoc />
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            var outgoingMessages = context.GetOrAdd(OutgoingMessagesItemsKey, () =>
            {
                var messages = new ConcurrentQueue <OutgoingMessage>();

                context.OnCommitted(tc => SendOutgoingMessages(context, messages));

                return(messages);
            });

            outgoingMessages.Enqueue(new OutgoingMessage(destinationAddress, message, isExpress: message.Headers.ContainsKey(Headers.Express)));
        }
 Task <ConnectionWrapper> GetConnection(ITransactionContext context)
 {
     return(context
            .GetOrAdd(CurrentConnectionKey,
                      async() =>
     {
         var dbConnection = await _connectionHelper.GetConnection();
         var connectionWrapper = new ConnectionWrapper(dbConnection);
         context.OnCommitted(async() => await dbConnection.Complete());
         context.OnDisposed(() => connectionWrapper.Dispose());
         return connectionWrapper;
     }));
 }
        /// <summary>
        /// Sends the given <see cref="TransportMessage"/> to the queue with the specified globally addressable name
        /// </summary>
        public async Task Send(string destinationAddress, TransportMessage transportMessage, ITransactionContext context)
        {
            var outgoingMessages = context.GetOrAdd("outgoing-messages", () =>
            {
                var messagesToSend = new ConcurrentQueue <MessageToSend>();

                context.OnCommitted(() =>
                {
                    var messagesByQueue = messagesToSend
                                          .GroupBy(m => m.DestinationAddress)
                                          .ToList();

                    return(Task.WhenAll(messagesByQueue.Select(async batch =>
                    {
                        var queueName = batch.Key;
                        var queue = GetQueue(queueName);

                        await Task.WhenAll(batch.Select(async message =>
                        {
                            var headers = message.Headers.Clone();
                            var timeToBeReceivedOrNull = GetTimeToBeReceivedOrNull(headers);
                            var queueVisibilityDelayOrNull = GetQueueVisibilityDelayOrNull(headers);
                            var cloudQueueMessage = Serialize(headers, message.Body);

                            try
                            {
                                await queue.AddMessageAsync(
                                    cloudQueueMessage,
                                    timeToBeReceivedOrNull,
                                    queueVisibilityDelayOrNull,
                                    ExponentialRetryRequestOptions,
                                    new OperationContext()
                                    );
                            }
                            catch (Exception exception)
                            {
                                var errorText = $"Could not send message with ID {cloudQueueMessage.Id} to '{message.DestinationAddress}'";

                                throw new RebusApplicationException(exception, errorText);
                            }
                        }));
                    })));
                });

                return(messagesToSend);
            });

            var messageToSend = new MessageToSend(destinationAddress, transportMessage.Headers, transportMessage.Body);

            outgoingMessages.Enqueue(messageToSend);
        }
 public static UnitOfWork GetConnection(this ITransactionContext context, OracleFactory factory)
 {
     return(context.GetOrAdd(ConnectionKey, () =>
     {
         var connection = factory.Open();
         context.OnCommitted(() =>
         {
             connection.Complete();
             return Task.CompletedTask;
         });
         context.OnDisposed(connection.Dispose);
         return connection;
     }));
 }
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
        public async Task SendAsync(TransportMessage message, ITransactionContext context)
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
        {
            var outgoingMessages = context.GetOrAdd(AmazonConstaints.OutgoingMessagesItemsKey, () =>
            {
                var sendMessageBatchRequestEntries = new ConcurrentQueue <AmazonOutgoingMessage>();

                context.OnCommitted(() => SendOutgoingMessages(sendMessageBatchRequestEntries, context));

                return(sendMessageBatchRequestEntries);
            });

            outgoingMessages.Enqueue(new AmazonOutgoingMessage(_destinationAddress, message));
        }
Пример #21
0
 async Task <MySqlConnection> GetConnection(ITransactionContext context)
 {
     return(context
            .GetOrAdd(CurrentConnectionKey, () =>
     {
         var dbConnection = _connectionHelper.GetConnection().Result;
         context.OnCommitted(async ctx => dbConnection.Complete());
         context.OnDisposed(ctx =>
         {
             dbConnection.Dispose();
         });
         return dbConnection;
     }));
 }
Пример #22
0
        /// <summary>
        /// Enqueues a message in-mem to be sent when the transaction context is committed
        /// </summary>
        /// <inheritdoc />
        public Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            var outgoingMessages = context.GetOrAdd("outgoing-messages", () =>
            {
                var messages = new ConcurrentQueue <OutgoingMessage>();

                context.OnCommitted(async() => await SendOutgoingMessages(messages, context));

                return(messages);
            });

            outgoingMessages.Enqueue(new OutgoingMessage(message, destinationAddress));

            return(TaskCompletedResult);
        }
Пример #23
0
 Task <IDbConnection> GetConnection(ITransactionContext context)
 {
     return(context
            .GetOrAdd(CurrentConnectionKey,
                      async() =>
     {
         var dbConnection = await _connectionProvider.GetConnection();
         context.OnCommitted(async() => await dbConnection.Complete());
         context.OnDisposed(() =>
         {
             dbConnection.Dispose();
         });
         return dbConnection;
     }));
 }
Пример #24
0
        public Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            if (destinationAddress == null)
            {
                throw new ArgumentNullException("destinationAddress");
            }
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            var outputQueue       = context.GetOrAdd(OutgoingQueueContextKey, () => new InMemOutputQueue());
            var contextActionsSet = context.GetOrAdd(OutgoingQueueContextActionIsSetKey, () => false);

            if (!contextActionsSet)
            {
                context.OnCommitted(async() =>
                {
                    var client = GetClientFromTransactionContext(context);
                    var messageSendRequests = outputQueue.GetMessages();
                    var tasks = messageSendRequests.Select(r => client.SendMessageBatchAsync(new SendMessageBatchRequest(r.DestinationAddressUrl, r.Messages.ToList())));

                    var response = await Task.WhenAll(tasks);
                    if (response.Any(r => r.Failed.Any()))
                    {
                        GenerateErrorsAndThrow(response);
                    }
                });
                context.OnAborted(outputQueue.Clear);

                context.Items[OutgoingQueueContextActionIsSetKey] = true;
            }

            var sendMessageRequest = new SendMessageBatchRequestEntry()
            {
                MessageAttributes = CreateAttributesFromHeaders(message.Headers),
                MessageBody       = GetBody(message.Body),
                Id = message.Headers.GetValueOrNull(Headers.MessageId) ?? Guid.NewGuid().ToString(),
            };

            outputQueue.AddMessage(GetDestinationQueueUrlByName(destinationAddress, context), sendMessageRequest);

            return(_emptyTask);
        }
        public Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            var outgoingMessages = context.GetOrAdd(OutgoingMessagesItemsKey, () =>
            {
                var messages = new ConcurrentQueue <TransportMessage>();

                context.OnCommitted(tc => StoreOutgoingMessages(messages));

                return(messages);
            });

            message.Headers.Add(OutboxHeaders.Recipient, destinationAddress);

            outgoingMessages.Enqueue(message);

            return(Task.CompletedTask);
        }
Пример #26
0
 ConnectionWrapper GetConnection(ITransactionContext context)
 {
     return(context
            .GetOrAdd(CurrentConnectionKey,
                      () =>
     {
         var dbConnection = _connectionHelper.GetConnection();
         var connectionWrapper = new ConnectionWrapper(dbConnection);
         context.OnCommitted(() =>
         {
             dbConnection.Complete();
             return Task.CompletedTask;
         });
         context.OnDisposed(() => connectionWrapper.Dispose());
         return connectionWrapper;
     }));
 }
Пример #27
0
 Task <ConnectionWrapper> GetConnection(ITransactionContext context)
 {
     return(context
            .GetOrAdd(CurrentConnectionKey,
                      async() =>
     {
         await Task.CompletedTask;
         var dbConnection = _connectionHelper.GetConnection();
         var connectionWrapper = new ConnectionWrapper(dbConnection);
         context.OnCommitted(() =>
         {
             dbConnection.Complete();
             return Task.FromResult(0);
         });
         context.OnDisposed(() => connectionWrapper.Dispose());
         return connectionWrapper;
     }));
 }
Пример #28
0
        /// <summary>
        /// Sends the specified message to the logical queue specified by <paramref name="destinationQueueName"/> by writing
        /// a JSON serialied text to a file in the corresponding directory. The actual write operation is delayed until
        /// the commit phase of the queue transaction unless we're non-transactional, in which case it is written immediately.
        /// </summary>
        public async Task Send(string destinationQueueName, TransportMessage message, ITransactionContext context)
        {
            EnsureQueueInitialized(destinationQueueName);

            var destinationDirectory = GetDirectoryForQueueNamed(destinationQueueName);

            var serializedMessage = Serialize(message);
            var fileName          = GetNextFileName();
            var fullPath          = Path.Combine(destinationDirectory, fileName);

            context.OnCommitted(async() =>
            {
                using (var stream = File.OpenWrite(fullPath))
                    using (var writer = new StreamWriter(stream, FavoriteEncoding))
                    {
                        await writer.WriteAsync(serializedMessage);
                    }
            });
        }
        /// <summary>
        /// Responsible for releasing the lease on message failure and removing the message on transaction commit
        /// </summary>
        /// <param name="context">Transaction context of the message processing</param>
        /// <param name="messageId">Identifier of the message currently being processed</param>
        private void ApplyTransactionSemantics(ITransactionContext context, long messageId)
        {
            AutomaticLeaseRenewer renewal = null;

            if (_automaticLeaseRenewal == true)
            {
                renewal = new AutomaticLeaseRenewer(ReceiveTableName.QualifiedName, messageId, ConnectionProvider, _automaticLeaseRenewalIntervalMilliseconds, _leaseIntervalMilliseconds);
            }

            context.OnAborted(
                () =>
            {
                renewal?.Dispose();

                AsyncHelpers.RunSync(() => UpdateLease(ConnectionProvider, ReceiveTableName.QualifiedName, messageId, null));
            }
                );

            context.OnCommitted(
                async() =>
            {
                renewal?.Dispose();

                // Delete the message
                using (var deleteConnection = await ConnectionProvider.GetConnection())
                {
                    using (var deleteCommand = deleteConnection.CreateCommand())
                    {
                        deleteCommand.CommandType = CommandType.Text;
                        deleteCommand.CommandText = $@"
DELETE
FROM	{ReceiveTableName.QualifiedName} WITH (ROWLOCK)
WHERE	id = @id
";
                        deleteCommand.Parameters.Add("@id", SqlDbType.BigInt).Value = messageId;
                        deleteCommand.ExecuteNonQuery();
                    }

                    await deleteConnection.Complete();
                }
            }
                );
        }
Пример #30
0
        /// <summary>
        /// Sends the specified message to the logical queue specified by <paramref name="destinationQueueName"/> by writing
        /// a JSON serialied text to a file in the corresponding directory. The actual write operation is delayed until
        /// the commit phase of the queue transaction unless we're non-transactional, in which case it is written immediately.
        /// </summary>
        public async Task Send(string destinationQueueName, TransportMessage message, ITransactionContext context)
        {
            EnsureQueueInitialized(destinationQueueName);

            var destinationDirectory = GetDirectoryForQueueNamed(destinationQueueName);

            var serializedMessage = Serialize(message);
            var fileName = GetNextFileName();
            var fullPath = Path.Combine(destinationDirectory, fileName);

            context.OnCommitted(async () =>
            {
                using (var stream = File.OpenWrite(fullPath))
                using (var writer = new StreamWriter(stream, FavoriteEncoding))
                {
                    await writer.WriteAsync(serializedMessage);
                }
            });
        }
        ConcurrentDictionary <string, ConcurrentQueue <TransportMessage> > GetOutgoingMessages(ITransactionContext context)
        {
            return(context.GetOrAdd(OutgoingMessagesKey, () =>
            {
                var destinations = new ConcurrentDictionary <string, ConcurrentQueue <TransportMessage> >();

                context.OnCommitted(async() =>
                {
                    // send outgoing messages
                    foreach (var destinationAndMessages in destinations)
                    {
                        var destinationAddress = destinationAndMessages.Key;
                        var messages = destinationAndMessages.Value;

                        var sendTasks = messages
                                        .Select(async message =>
                        {
                            await GetRetrier().Execute(async() =>
                            {
                                using (var brokeredMessageToSend = CreateBrokeredMessage(message))
                                {
                                    try
                                    {
                                        await GetQueueClient(destinationAddress).SendAsync(brokeredMessageToSend);
                                    }
                                    catch (MessagingEntityNotFoundException exception)
                                    {
                                        // do NOT rethrow as MessagingEntityNotFoundException because it has its own ToString that swallows most of the info!!
                                        throw new MessagingException($"Could not send to '{destinationAddress}'!", false, exception);
                                    }
                                }
                            });
                        })
                                        .ToArray();

                        await Task.WhenAll(sendTasks);
                    }
                });

                return destinations;
            }));
        }
Пример #32
0
        ConcurrentDictionary <string, ConcurrentQueue <TransportMessage> > GetOutgoingMessages(ITransactionContext context)
        {
            return(context.GetOrAdd(OutgoingMessagesKey, () =>
            {
                var destinations = new ConcurrentDictionary <string, ConcurrentQueue <TransportMessage> >();

                context.OnCommitted(async() =>
                {
                    // send outgoing messages
                    foreach (var destinationAndMessages in destinations)
                    {
                        var destinationAddress = destinationAndMessages.Key;
                        var messages = destinationAndMessages.Value;

                        var sendTasks = messages
                                        .Select(async message =>
                        {
                            await GetRetrier().Execute(async() =>
                            {
                                using (var brokeredMessageToSend = CreateBrokeredMessage(message))
                                {
                                    try
                                    {
                                        await Send(destinationAddress, brokeredMessageToSend);
                                    }
                                    catch (MessagingEntityNotFoundException exception)
                                    {
                                        throw new MessagingEntityNotFoundException(string.Format("Could not send to '{0}'!", destinationAddress), exception);
                                    }
                                }
                            });
                        })
                                        .ToArray();

                        await Task.WhenAll(sendTasks);
                    }
                });

                return destinations;
            }));
        }
Пример #33
0
    /// <summary>
    /// Sends
    /// </summary>
    /// <param name="destinationAddress"></param>
    /// <param name="message"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
    {
        // this timestamp will only be used in the file names of message files written to approach some kind
        // of global ordering - individual messages sent from this context will have sequence numbers on them
        // in addition to the timestamp
        var time = _rebusTime.Now;

        var outgoingMessages = context.GetOrAdd("file-system-transport-outgoing-messages", () =>
        {
            var queue = new ConcurrentQueue <OutgoingMessage>();

            context.OnCommitted(_ => SendOutgoingMessages(queue, time));
            context.OnAborted(_ => AbortOutgoingMessages(queue));

            return(queue);
        });

        var outgoingMessage = await OutgoingMessage.WriteTemp(GetDirectory(destinationAddress), message);

        outgoingMessages.Enqueue(outgoingMessage);
    }
Пример #34
0
            public async Task <TransportMessage> Receive(ITransactionContext context)
            {
                var transportMessage = await _innerTransport.Receive(context);

                if (transportMessage == null)
                {
                    return(null);
                }

                var shouldFailThisTime = Interlocked.Increment(ref _failCounter) % _failFactor == 0;

                if (shouldFailThisTime)
                {
                    context.OnCommitted(async() =>
                    {
                        throw new Exception("oh noes!!!!!");
                    });
                }

                return(transportMessage);
            }
Пример #35
0
        /// <summary>
        /// Sends the given <see cref="TransportMessage"/> to the queue with the specified globally addressable name
        /// </summary>
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            context.OnCommitted(async () =>
            {
                var queue = GetQueue(destinationAddress);
                var messageId = Guid.NewGuid().ToString();
                var popReceipt = Guid.NewGuid().ToString();
                var timeToBeReceived = GetTimeToBeReceivedOrNull(message);
                var cloudQueueMessage = Serialize(message, messageId, popReceipt);

                try
                {
                    var options = new QueueRequestOptions {RetryPolicy = new ExponentialRetry()};
                    var operationContext = new OperationContext();

                    await queue.AddMessageAsync(cloudQueueMessage, timeToBeReceived, null, options, operationContext);
                }
                catch (Exception exception)
                {
                    throw new RebusApplicationException(string.Format("Could not send message with ID {0} to '{1}'", cloudQueueMessage.Id, destinationAddress), exception);
                }
            });
        }
Пример #36
0
        ConcurrentDictionary<string, ConcurrentQueue<TransportMessage>> GetOutgoingMessages(ITransactionContext context)
        {
            return context.GetOrAdd(OutgoingMessagesKey, () =>
            {
                var destinations = new ConcurrentDictionary<string, ConcurrentQueue<TransportMessage>>();

                context.OnCommitted(async () =>
                {
                    // send outgoing messages
                    foreach (var destinationAndMessages in destinations)
                    {
                        var destinationAddress = destinationAndMessages.Key;
                        var messages = destinationAndMessages.Value;

                        _log.Debug("Sending {0} messages to {1}", messages.Count, destinationAddress);

                        var sendTasks = messages
                            .Select(async message =>
                            {
                                await GetRetrier().Execute(async () =>
                                {
                                    using (var brokeredMessageToSend = CreateBrokeredMessage(message))
                                    {
                                        await GetQueueClient(destinationAddress).SendAsync(brokeredMessageToSend);
                                    }
                                });
                            })
                            .ToArray();

                        await Task.WhenAll(sendTasks);
                    }
                });

                return destinations;
            });
        }
Пример #37
0
 Task<IDbConnection> GetConnection(ITransactionContext context)
 {
     return context
         .GetOrAdd(CurrentConnectionKey,
             async () =>
             {
                 var dbConnection = await _connectionProvider.GetConnection();
                 context.OnCommitted(async () => await dbConnection.Complete());
                 context.OnDisposed(() =>
                 {
                     dbConnection.Dispose();
                 });
                 return dbConnection;
             });
 }
Пример #38
0
        /// <summary>
        /// Sends the given transport message to the specified destination address using MSMQ. Will use the existing <see cref="MessageQueueTransaction"/> stashed
        /// under the <see cref="CurrentTransactionKey"/> key in the given <paramref name="context"/>, or else it will create one and add it.
        /// </summary>
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            if (destinationAddress == null) throw new ArgumentNullException("destinationAddress");
            if (message == null) throw new ArgumentNullException("message");
            if (context == null) throw new ArgumentNullException("context");

            var logicalMessage = CreateMsmqMessage(message);

            var messageQueueTransaction = context.GetOrAdd(CurrentTransactionKey, () =>
            {
                var messageQueueTransaction1 = new MessageQueueTransaction();
                messageQueueTransaction1.Begin();

                context.OnCommitted(async () => messageQueueTransaction1.Commit());

                return messageQueueTransaction1;
            });

            var sendQueues = context.GetOrAdd(CurrentOutgoingQueuesKey, () =>
            {
                var messageQueues = new ConcurrentDictionary<string, MessageQueue>(StringComparer.InvariantCultureIgnoreCase);

                context.OnDisposed(() =>
                {
                    foreach (var messageQueue in messageQueues.Values)
                    {
                        messageQueue.Dispose();
                    }
                });

                return messageQueues;
            });

            var path = MsmqUtil.GetFullPath(destinationAddress);

            var sendQueue = sendQueues.GetOrAdd(path, _ =>
            {
                var messageQueue = new MessageQueue(path, QueueAccessMode.Send);

                return messageQueue;
            });

            sendQueue.Send(logicalMessage, messageQueueTransaction);
        }
        ConcurrentDictionary<string, ConcurrentQueue<TransportMessage>> GetOutgoingMessages(ITransactionContext context)
        {
            return context.GetOrAdd(OutgoingMessagesKey, () =>
            {
                var destinations = new ConcurrentDictionary<string, ConcurrentQueue<TransportMessage>>();

                context.OnCommitted(async () =>
                {
                    // send outgoing messages
                    foreach (var destinationAndMessages in destinations)
                    {
                        var destinationAddress = destinationAndMessages.Key;
                        var messages = destinationAndMessages.Value;

                        var sendTasks = messages
                            .Select(async message =>
                            {
                                await GetRetrier().Execute(async () =>
                                {
                                    using (var brokeredMessageToSend = MsgHelpers.CreateBrokeredMessage(message))
                                    {
                                        try
                                        {
                                            await GetQueueClient(destinationAddress).SendAsync(brokeredMessageToSend);
                                        }
                                        catch (MessagingEntityNotFoundException exception)
                                        {
                                            // do NOT rethrow as MessagingEntityNotFoundException because it has its own ToString that swallows most of the info!!
                                            throw new MessagingException($"Could not send to '{destinationAddress}'!", false, exception);
                                        }
                                    }
                                });
                            })
                            .ToArray();

                        await Task.WhenAll(sendTasks);
                    }
                });

                return destinations;
            });
        }
Пример #40
0
        /// <summary>
        /// Received the next available transport message from the input queue via MSMQ. Will create a new <see cref="MessageQueueTransaction"/> and stash
        /// it under the <see cref="CurrentTransactionKey"/> key in the given <paramref name="context"/>. If one already exists, an exception will be thrown
        /// (because we should never have to receive multiple messages in the same transaction)
        /// </summary>
        public async Task<TransportMessage> Receive(ITransactionContext context)
        {
            if (context == null) throw new ArgumentNullException("context");
            if (_inputQueueName == null)
            {
                throw new InvalidOperationException("This MSMQ transport does not have an input queue, hence it is not possible to reveive anything");
            }

            var queue = GetInputQueue();

            if (context.Items.ContainsKey(CurrentTransactionKey))
            {
                throw new InvalidOperationException("Tried to receive with an already existing MSMQ queue transaction - while that is possible, it's an indication that something is wrong!");
            }

            var messageQueueTransaction = new MessageQueueTransaction();
            messageQueueTransaction.Begin();

            context.OnCommitted(async () => messageQueueTransaction.Commit());
            context.OnDisposed(() => messageQueueTransaction.Dispose());

            context.Items[CurrentTransactionKey] = messageQueueTransaction;

            try
            {
                var message = queue.Receive(TimeSpan.FromSeconds(1), messageQueueTransaction);
                if (message == null)
                {
                    messageQueueTransaction.Abort();
                    return null;
                }

                var headers = _extensionSerializer.Deserialize(message.Extension, message.Id);
                var body = new byte[message.BodyStream.Length];

                await message.BodyStream.ReadAsync(body, 0, body.Length);

                return new TransportMessage(headers, body);
            }
            catch (MessageQueueException exception)
            {
                if (exception.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
                {
                    return null;
                }

                if (exception.MessageQueueErrorCode == MessageQueueErrorCode.InvalidHandle)
                {
                    _log.Info("Queue handle for '{0}' was invalid - will try to reinitialize the queue", _inputQueueName);
                    ReinitializeInputQueue();
                }

                if (exception.MessageQueueErrorCode == MessageQueueErrorCode.QueueDeleted)
                {
                    _log.Warn("Queue '{0}' was deleted - will not receive any more messages", _inputQueueName);
                    return null;
                }

                throw new IOException(
                    string.Format("Could not receive next message from MSMQ queue '{0}'", _inputQueueName),
                    exception);
            }
        }
Пример #41
0
        public async Task<TransportMessage> Receive(ITransactionContext context)
        {
            if (_inputQueueAddress == null)
            {
                throw new InvalidOperationException("This Azure Service Bus transport does not have an input queue, hence it is not possible to reveive anything");
            }

            using (await _bottleneck.Enter())
            {
                var brokeredMessage = await ReceiveBrokeredMessage();

                if (brokeredMessage == null) return null;

                var headers = brokeredMessage.Properties
                    .Where(kvp => kvp.Value is string)
                    .ToDictionary(kvp => kvp.Key, kvp => (string)kvp.Value);

                var messageId = headers.GetValueOrNull(Headers.MessageId);
                var leaseDuration = (brokeredMessage.LockedUntilUtc - DateTime.UtcNow);
                var lockRenewalInterval = TimeSpan.FromMinutes(0.8 * leaseDuration.TotalMinutes);

                var renewalTask = GetRenewalTaskOrFakeDisposable(messageId, brokeredMessage, lockRenewalInterval);

                context.OnAborted(() =>
                {
                    renewalTask.Dispose();

                    try
                    {
                        brokeredMessage.Abandon();
                    }
                    catch (Exception exception)
                    {
                        // if it fails, it'll be back on the queue anyway....
                        _log.Warn("Could not abandon message: {0}", exception);
                    }
                });

                context.OnCommitted(async () => renewalTask.Dispose());

                context.OnCompleted(async () =>
                {
                    await brokeredMessage.CompleteAsync();
                });

                context.OnDisposed(() =>
                {
                    renewalTask.Dispose();
                    brokeredMessage.Dispose();
                });

                using (var memoryStream = new MemoryStream())
                {
                    await brokeredMessage.GetBody<Stream>().CopyToAsync(memoryStream);
                    return new TransportMessage(headers, memoryStream.ToArray());
                }
            }
        }
Пример #42
0
        public async Task<TransportMessage> Receive(ITransactionContext context, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (Address == null)
            {
                throw new InvalidOperationException("This RabbitMQ transport does not have an input queue - therefore, it is not possible to reveive anything");
            }

            try
            {
                EnsureConsumerInitialized();

                var consumer = _consumer;

                // initialization must have failed
                if (consumer == null) return null;

                var model = consumer.Model;

                if (!model.IsOpen)
                {
                    // something is wrong - we would not be able to ACK messages - force re-initialization to happen
                    _consumer = null;

                    // try to get rid of the consumer we have here
                    try
                    {
                        model.Dispose();
                    }
                    catch { }
                }

                BasicDeliverEventArgs result;
                if (!consumer.Queue.Dequeue(TwoSeconds, out result)) return null;

                var deliveryTag = result.DeliveryTag;

                context.OnCommitted(async () =>
                {
                    model.BasicAck(deliveryTag, false);
                });

                context.OnAborted(() =>
                {
                    // we might not be able to do this, but it doesn't matter that much if it succeeds
                    try
                    {
                        model.BasicNack(deliveryTag, false, true);
                    }
                    catch { }
                });

                return CreateTransportMessage(result);
            }
            catch (EndOfStreamException exception)
            {
                ClearConsumer();

                throw new RebusApplicationException(exception,
                    "Queue throw EndOfStreamException(meaning it was canceled by rabbitmq)");
            }
            catch (Exception exception)
            {
                ClearConsumer();

                Thread.Sleep(1000);

                throw new RebusApplicationException(exception,
                    $"unexpected exception thrown while trying to dequeue a message from rabbitmq, queue address: {Address}");
            }
        }
Пример #43
0
        ConcurrentDictionary<string, ConcurrentQueue<TransportMessage>> GetOutgoingMessages(ITransactionContext context)
        {
            return context.GetOrAdd(OutgoingMessagesKey, () =>
            {
                var destinations = new ConcurrentDictionary<string, ConcurrentQueue<TransportMessage>>();

                context.OnCommitted(async () =>
                {
                    // send outgoing messages
                    foreach (var destinationAndMessages in destinations)
                    {
                        var destinationAddress = destinationAndMessages.Key;
                        var messages = destinationAndMessages.Value;

                        var sendTasks = messages
                            .Select(async message =>
                            {
                                await GetRetrier().Execute(async () =>
                                {
                                    using (var brokeredMessageToSend = CreateBrokeredMessage(message))
                                    {
                                        try
                                        {
                                            await Send(destinationAddress, brokeredMessageToSend);
                                        }
                                        catch (MessagingEntityNotFoundException exception)
                                        {
                                            throw new MessagingEntityNotFoundException($"Could not send to '{destinationAddress}'!", exception);
                                        }
                                    }
                                });
                            })
                            .ToArray();

                        await Task.WhenAll(sendTasks);
                    }
                });

                return destinations;
            });
        }
Пример #44
0
        public async Task<TransportMessage> Receive(ITransactionContext context)
        {
            using (await _bottleneck.Enter())
            {
                var brokeredMessage = await ReceiveBrokeredMessage();

                if (brokeredMessage == null) return null;

                var headers = brokeredMessage.Properties
                    .Where(kvp => kvp.Value is string)
                    .ToDictionary(kvp => kvp.Key, kvp => (string)kvp.Value);

                var messageId = headers.GetValueOrNull(Headers.MessageId);

                _log.Debug("Received brokered message with ID {0}", messageId);

                var leaseDuration = (brokeredMessage.LockedUntilUtc - DateTime.UtcNow);
                var lockRenewalInterval = TimeSpan.FromMinutes(0.8 * leaseDuration.TotalMinutes);

                var renewalTask = GetRenewalTaskOrFakeDisposable(messageId, brokeredMessage, lockRenewalInterval);

                context.OnAborted(() =>
                {
                    renewalTask.Dispose();

                    _log.Debug("Abandoning message with ID {0}", messageId);
                    try
                    {
                        brokeredMessage.Abandon();
                    }
                    catch (Exception exception)
                    {
                        // if it fails, it'll be back on the queue anyway....
                        _log.Warn("Could not abandon message: {0}", exception);
                    }
                });

                context.OnCommitted(async () =>
                {
                    renewalTask.Dispose();
                });

                context.OnCompleted(async () =>
                {
                    _log.Debug("Completing message with ID {0}", messageId);

                    await GetRetrier().Execute(() => brokeredMessage.CompleteAsync());
                });

                context.OnDisposed(() =>
                {
                    renewalTask.Dispose();

                    _log.Debug("Disposing message with ID {0}", messageId);
                    brokeredMessage.Dispose();
                });

                return new TransportMessage(headers, brokeredMessage.GetBody<byte[]>());
            }
        }
Пример #45
0
        public Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            if (destinationAddress == null) throw new ArgumentNullException("destinationAddress");
            if (message == null) throw new ArgumentNullException("message");
            if (context == null) throw new ArgumentNullException("context");

            var outputQueue = context.GetOrAdd(OutgoingQueueContextKey, () => new InMemOutputQueue());
            var contextActionsSet = context.GetOrAdd(OutgoingQueueContextActionIsSetKey, () => false);

            if (!contextActionsSet)
            {
                context.OnCommitted(async () =>
                                          {

                                              var client = GetClientFromTransactionContext(context);
                                              var messageSendRequests = outputQueue.GetMessages();
                                              var tasks = messageSendRequests.Select(r => client.SendMessageBatchAsync(new SendMessageBatchRequest(r.DestinationAddressUrl, r.Messages.ToList())));

                                              var response = await Task.WhenAll(tasks);
                                              if (response.Any(r => r.Failed.Any()))
                                              {
                                                  GenerateErrorsAndThrow(response);
                                              }

                                          });
                context.OnAborted(outputQueue.Clear);

                context.Items[OutgoingQueueContextActionIsSetKey] = true;
            }

            var sendMessageRequest = new SendMessageBatchRequestEntry()
                                     {

                                         MessageAttributes = CreateAttributesFromHeaders(message.Headers),
                                         MessageBody = GetBody(message.Body),
                                         Id = message.Headers.GetValueOrNull(Headers.MessageId) ?? Guid.NewGuid().ToString(),
                                     };

            outputQueue.AddMessage(GetDestinationQueueUrlByName(destinationAddress, context), sendMessageRequest);

            return _emptyTask;
        }
Пример #46
0
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            if (destinationAddress == null) throw new ArgumentNullException(nameof(destinationAddress));
            if (message == null) throw new ArgumentNullException(nameof(message));
            if (context == null) throw new ArgumentNullException(nameof(context));

            var outgoingMessages = context.GetOrAdd(OutgoingMessagesItemsKey, () =>
            {
                var sendMessageBatchRequestEntries = new ConcurrentQueue<OutgoingMessage>();

                context.OnCommitted(async () =>
                {
                    await SendOutgoingMessages(sendMessageBatchRequestEntries, context);
                });

                return sendMessageBatchRequestEntries;
            });

            outgoingMessages.Enqueue(new OutgoingMessage(destinationAddress, message));
        }