예제 #1
0
 protected override Task UpdateQueuedMessage(SQLQueuedMessage queuedMessage, DateTime? acknowledged,
     DateTime? abandoned, int attempts)
 {
     CheckDisposed();
     var op =
         new SQLiteOperation(() => base.UpdateQueuedMessage(queuedMessage, acknowledged, abandoned, attempts));
     _operationQueue.Post(op);
     return op.Task;
 }
예제 #2
0
 public SQLQueuedMessageContext(SQLQueuedMessage queuedMessage)
 {
     _queuedMessage = queuedMessage;
 }
예제 #3
0
        protected virtual Task UpdateQueuedMessage(SQLQueuedMessage queuedMessage, DateTime? acknowledged,
            DateTime? abandoned, int attempts)
        {
            var connection = _connectionProvider.GetConnection();
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required))
                {
                    using (var command = connection.CreateCommand())
                    {
                        command.CommandType = CommandType.Text;
                        command.CommandText = _dialect.UpdateQueuedMessageCommand;
                        command.SetParameter(_dialect.MessageIdParameterName,
                            (Guid) queuedMessage.Message.Headers.MessageId);
                        command.SetParameter(_dialect.QueueNameParameterName, (string) _queueName);
                        command.SetParameter(_dialect.AcknowledgedParameterName, acknowledged);
                        command.SetParameter(_dialect.AbandonedParameterName, abandoned);
                        command.SetParameter(_dialect.AttemptsParameterName, attempts);

                        command.ExecuteNonQuery();
                    }
                    scope.Complete();
                }
            }
            finally
            {
                _connectionProvider.ReleaseConnection(connection);
            }

            // SQL calls are not async to avoid the need for TransactionAsyncFlowOption
            // and dependency on .NET 4.5.1 and later
            return Task.FromResult(true);
        }
예제 #4
0
        protected virtual Task<IEnumerable<SQLQueuedMessage>> SelectQueuedMessages()
        {
            var queuedMessages = new List<SQLQueuedMessage>();
            var connection = _connectionProvider.GetConnection();
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required))
                {
                    using (var command = connection.CreateCommand())
                    {
                        command.CommandType = CommandType.Text;
                        command.CommandText = _dialect.SelectQueuedMessagesCommand;
                        command.SetParameter(_dialect.QueueNameParameterName, (string) _queueName);

                        using (var reader = command.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                var messageContent = reader.GetString("MessageContent");
                                var headers = DeserializeHeaders(reader.GetString("Headers"));
                                var senderPrincipal = DeserializePrincipal(reader.GetString("SenderPrincipal"));
                                var message = new Message(headers, messageContent);
                                var attempts = reader.GetInt("Attempts").GetValueOrDefault(0);
                                var queuedMessage = new SQLQueuedMessage(message, senderPrincipal, attempts);
                                queuedMessages.Add(queuedMessage);
                            }
                        }
                    }
                    scope.Complete();
                }
            }
            finally
            {
                _connectionProvider.ReleaseConnection(connection);
            }

            // SQL calls are not async to avoid the need for TransactionAsyncFlowOption
            // and dependency on .NET 4.5.1 and later
            return Task.FromResult(queuedMessages.AsEnumerable());
        }
예제 #5
0
        protected virtual Task<SQLQueuedMessage> InsertQueuedMessage(Message message, IPrincipal senderPrincipal)
        {
            SQLQueuedMessage queuedMessage;
            var connection = _connectionProvider.GetConnection();
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required))
                {
                    using (var command = connection.CreateCommand())
                    {
                        command.CommandType = CommandType.Text;
                        command.CommandText = _dialect.InsertQueuedMessageCommand;

                        var headers = message.Headers;

                        command.SetParameter(_dialect.MessageIdParameterName, (Guid) headers.MessageId);
                        command.SetParameter(_dialect.QueueNameParameterName, (string) _queueName);
                        command.SetParameter(_dialect.MessageNameParameterName, (string) headers.MessageName);
                        command.SetParameter(_dialect.OriginationParameterName,
                            headers.Origination == null ? null : headers.Origination.ToString());
                        command.SetParameter(_dialect.DestinationParameterName,
                            headers.Destination == null ? null : headers.Destination.ToString());
                        command.SetParameter(_dialect.ReplyToParameterName,
                            headers.ReplyTo == null ? null : headers.ReplyTo.ToString());
                        command.SetParameter(_dialect.ExpiresParameterName, headers.Expires);
                        command.SetParameter(_dialect.ContentTypeParameterName, headers.ContentType);
                        command.SetParameter(_dialect.SenderPrincipalParameterName, SerializePrincipal(senderPrincipal));
                        command.SetParameter(_dialect.HeadersParameterName, SerializeHeaders(headers));
                        command.SetParameter(_dialect.MessageContentParameterName, message.Content);

                        command.ExecuteNonQuery();
                    }
                    scope.Complete();
                }
                queuedMessage = new SQLQueuedMessage(message, senderPrincipal);
            }
            finally
            {
                _connectionProvider.ReleaseConnection(connection);
            }

            // SQL calls are not async to avoid the need for TransactionAsyncFlowOption
            // and dependency on .NET 4.5.1 and later
            return Task.FromResult(queuedMessage);
        }
예제 #6
0
        // ReSharper disable once UnusedMethodReturnValue.Local
        protected async Task ProcessQueuedMessage(SQLQueuedMessage queuedMessage, CancellationToken cancellationToken)
        {
            var messageId = queuedMessage.Message.Headers.MessageId;
            var attemptCount = queuedMessage.Attempts;
            var abandoned = false;
            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
            while (!abandoned && attemptCount < _maxAttempts)
            {
                attemptCount++;

                Log.DebugFormat("Processing queued message {0} (attempt {1} of {2})...", messageId, attemptCount,
                    _maxAttempts);

                var context = new SQLQueuedMessageContext(queuedMessage);
                cancellationToken.ThrowIfCancellationRequested();

                await _concurrentMessageProcessingSlot.WaitAsync(cancellationToken);
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    var message = queuedMessage.Message;
                    await _listener.MessageReceived(message, context, cancellationToken);
                    if (_autoAcknowledge && !context.Acknowledged)
                    {
                        await context.Acknowledge();
                    }
                }
                catch (Exception ex)
                {
                    Log.WarnFormat("Unhandled exception handling queued message {0}", ex, messageId);
                }
                finally
                {
                    _concurrentMessageProcessingSlot.Release();
                }

                if (context.Acknowledged)
                {
                    Log.DebugFormat("Message acknowledged.  Marking message {0} as acknowledged...", messageId);
                    // TODO: Implement journaling
                    await UpdateQueuedMessage(queuedMessage, DateTime.UtcNow, null, attemptCount);
                    Log.DebugFormat("Message {0} acknowledged successfully", messageId);
                    return;
                }
                
                if (attemptCount >= _maxAttempts)
                {
                    Log.WarnFormat("Maximum attempts to proces message {0} exceeded", messageId);
                    abandoned = true;
                }

                if (abandoned)
                {
                    await UpdateQueuedMessage(queuedMessage, null, DateTime.UtcNow, attemptCount);
                    return;
                }

                await UpdateQueuedMessage(queuedMessage, null, null, attemptCount);

                Log.DebugFormat("Message not acknowledged.  Retrying in {0}...", _retryDelay);
                await Task.Delay(_retryDelay, cancellationToken);
            }
        }