Beispiel #1
0
        private void OnTimeoutCallback(object state)
        {
            bool haveTimeoutMessages = false;

            timeoutMessageIds.Read(reader =>
                                   haveTimeoutMessages = reader.HasAnyBefore(CurrentTime)
                                   );

            if (haveTimeoutMessages == false)
            {
                return;
            }

            timeoutMessageIds.Write(writer =>
            {
                KeyValuePair <DateTime, List <IList <long> > > pair;
                while (writer.TryRemoveFirstUntil(CurrentTime, out pair))
                {
                    if (pair.Key > CurrentTime)
                    {
                        return;
                    }

                    foreach (var messageIdCollection in pair.Value)
                    {
                        try
                        {
                            logger.DebugFormat("Moving message {0} to main queue: {1}",
                                               messageIdCollection, queue.QueueName);
                            using (var tx = queue.BeginTransaction())
                            {
                                foreach (var id in messageIdCollection)
                                {
                                    var message = queue.PeekByIdIgnoringProcessingUntil(id);
                                    if (message == null)
                                    {
                                        logger.DebugFormat("Failed to move message {0} to main queue: {1}, not found.",
                                                           id, queue.QueueName);
                                        continue;
                                    }
                                    queue.MoveTo(null, message);
                                }
                                tx.Transaction.Commit();
                            }
                        }
                        catch (Exception)
                        {
                            logger.DebugFormat(
                                "Could not move message {0} to main queue: {1}",
                                pair.Value,
                                queue.QueueName);

                            if ((CurrentTime - pair.Key).TotalMinutes >= 1.0D)
                            {
                                logger.DebugFormat("Tried to send message {0} for over a minute, giving up",
                                                   pair.Value);
                                continue;
                            }

                            writer.Add(pair.Key, messageIdCollection);
                            logger.DebugFormat("Will retry moving message {0} to main queue {1} in 1 second",
                                               pair.Value,
                                               queue.QueueName);
                        }
                    }
                }
            });
        }
        private void ReceiveMessage(object context)
        {
            int sleepTime = 1;

            while (shouldContinue)
            {
                Thread.Sleep(sleepTime);
                try
                {
                    using (var tx = _sqlQueueManager.BeginTransaction())
                    {
                        if (!_sqlQueueManager.Peek(_queueId))
                        {
                            sleepTime += 100;
                            sleepTime  = Math.Min(sleepTime, SleepMax);
                            continue;
                        }
                        sleepTime = 1;
                        tx.Transaction.Commit();
                    }
                }
                catch (TimeoutException)
                {
                    logger.DebugFormat("Could not find a message on {0} during the timeout period.",
                                       queueEndpoint);
                    continue;
                }
                catch (SqlException e)
                {
                    logger.Warn("Could not get message from database.", e);
                    continue;
                }
                catch (ObjectDisposedException)
                {
                    logger.DebugFormat("Shutting down the transport for {0} thread {1}.", queueEndpoint, context);
                    return;
                }
                catch (InvalidOperationException e)
                {
                    logger.Error(
                        "An error occured while recieving a message, clearing connection pool and make a new attempt after some sleep.", e);

                    SqlConnection.ClearAllPools();
                    sleepTime = SleepMax;
                    continue;
                }
                catch (Exception e)
                {
                    logger.Error(
                        "An error occured while recieving a message, shutting down message processing thread",
                        e);
                    return;
                }

                if (shouldContinue == false)
                {
                    return;
                }

                Message message;
                try
                {
                    using (var tx = _sqlQueueManager.BeginTransaction())
                    {
                        message = _sqlQueueManager.Receive(_queueId, TimeSpan.FromSeconds(10));
                        tx.Transaction.Commit();
                    }
                }
                catch (TimeoutException)
                {
                    logger.DebugFormat("Could not find a message on {0} during the timeout period",
                                       queueEndpoint);
                    continue;
                }
                catch (SqlException e)
                {
                    logger.Debug("Could not get message from database.",
                                 e);
                    continue;
                }
                catch (InvalidOperationException e)
                {
                    logger.Error(
                        "An error occured while recieving a message, clearing connection pool and make a new attempt after some sleep.", e);

                    SqlConnection.ClearAllPools();
                    sleepTime = SleepMax;
                    continue;
                }
                catch (Exception e)
                {
                    logger.Error(
                        "An error occured while recieving a message, shutting down message processing thread",
                        e);
                    return;
                }

                if (message.ProcessedCount > numberOfRetries)
                {
                    using (var tx = _sqlQueueManager.BeginTransaction())
                    {
                        Queue.MoveTo(SubQueue.Errors.ToString(), message);
                        Queue.EnqueueDirectlyTo(SubQueue.Errors.ToString(), new MessagePayload
                        {
                            SentAt  = DateTime.UtcNow,
                            Data    = null,
                            Headers = new NameValueCollection
                            {
                                {
                                    "correlation-id", message.Id.ToString()
                                },
                                {
                                    "retries", message.ProcessedCount.ToString(CultureInfo.InvariantCulture)
                                }
                            }
                        });
                        tx.Transaction.Commit();
                    }
                    continue;
                }

                var messageWithTimer = new MessageWithTimer {
                    Message = message
                };
                var messageProcessingTimer = new Timer(extendMessageLeaaseIfMessageStillInProgress, messageWithTimer,
                                                       TimeSpan.FromSeconds(40), TimeSpan.FromMilliseconds(-1));
                messageWithTimer.Timer = messageProcessingTimer;

                try
                {
                    var msgType = (MessageType)Enum.Parse(typeof(MessageType), message.Headers["type"]);
                    logger.DebugFormat("Starting to handle message {0} of type {1} on {2}",
                                       message.Id,
                                       msgType,
                                       queueEndpoint);
                    switch (msgType)
                    {
                    case MessageType.AdministrativeMessageMarker:
                        ProcessMessage(message,
                                       AdministrativeMessageArrived,
                                       AdministrativeMessageProcessingCompleted,
                                       null,
                                       null);
                        break;

                    case MessageType.ShutDownMessageMarker:
                        //ignoring this one
                        using (var tx = _sqlQueueManager.BeginTransaction())
                        {
                            _sqlQueueManager.MarkMessageAsReady(message);
                            tx.Transaction.Commit();
                        }
                        break;

                    case MessageType.TimeoutMessageMarker:
                        var timeToSend = XmlConvert.ToDateTime(message.Headers["time-to-send"],
                                                               XmlDateTimeSerializationMode.Unspecified);
                        if (timeToSend > DateTime.Now)
                        {
                            timeout.Register(message);
                            using (var tx = queue.BeginTransaction())
                            {
                                queue.MoveTo(SubQueue.Timeout.ToString(), message);
                                tx.Transaction.Commit();
                            }
                        }
                        else
                        {
                            ProcessMessage(message,
                                           MessageArrived,
                                           MessageProcessingCompleted,
                                           BeforeMessageTransactionCommit,
                                           BeforeMessageTransactionRollback);
                        }
                        break;

                    default:
                        ProcessMessage(message,
                                       MessageArrived,
                                       MessageProcessingCompleted,
                                       BeforeMessageTransactionCommit,
                                       BeforeMessageTransactionRollback);
                        break;
                    }
                }
                catch (Exception exception)
                {
                    logger.Debug("Could not process message", exception);
                }
                message.FinishedProcessing = true;
            }
        }