/// <summary>
        /// Creates the messages to send.
        /// </summary>
        /// <param name="redisHeaders">The redis headers.</param>
        /// <param name="messages">The messages.</param>
        /// <param name="meta">The meta data, already serialized.</param>
        /// <param name="unixTimeFactory">The unix time factory.</param>
        /// <param name="messageIdFactory">The message identifier factory.</param>
        /// <param name="serializer">The composite serializer.</param>
        /// <returns></returns>
        public static List <EnqueueBatchLua.MessageToSend> CreateMessagesToSend(RedisHeaders redisHeaders,
                                                                                IReadOnlyCollection <QueueMessage <IMessage, IAdditionalMessageData> > messages,
                                                                                byte[] meta,
                                                                                IUnixTimeFactory unixTimeFactory,
                                                                                IGetMessageIdFactory messageIdFactory,
                                                                                ICompositeSerialization serializer)
        {
            var messagesToSend = new ConcurrentBag <EnqueueBatchLua.MessageToSend>();

            Parallel.ForEach(messages, m =>
            {
                //the correlation ID must be saved as a message header
                m.Message.SetHeader(redisHeaders.CorrelationId, new RedisQueueCorrelationIdSerialized((Guid)m.MessageData.CorrelationId.Id.Value));

                //check for delay and expiration
                long unixTimeStampDelay      = 0;
                long unixTimeStampExpiration = 0;
                if (m.MessageData.GetDelay().HasValue)
                {
                    // ReSharper disable once PossibleInvalidOperationException
                    unixTimeStampDelay = unixTimeFactory.Create().GetAddDifferenceMilliseconds(m.MessageData.GetDelay().Value);
                }
                // ReSharper disable once PossibleInvalidOperationException
                if (m.MessageData.GetExpiration().HasValue&& m.MessageData.GetExpiration().Value != TimeSpan.Zero)
                {
                    var unixTime = unixTimeFactory.Create();
                    var timeSpan = m.MessageData.GetExpiration();
                    if (timeSpan != null)
                    {
                        var timespan            = timeSpan.Value;
                        unixTimeStampExpiration = unixTime.GetAddDifferenceMilliseconds(timespan);
                    }
                }

                var serialized = serializer.Serializer.MessageToBytes(new MessageBody {
                    Body = m.Message.Body
                }, m.Message.Headers);
                m.Message.SetHeader(redisHeaders.Headers.StandardHeaders.MessageInterceptorGraph, serialized.Graph);

                messagesToSend.Add(new EnqueueBatchLua.MessageToSend
                {
                    Message         = serialized.Output,
                    Headers         = serializer.InternalSerializer.ConvertToBytes(m.Message.Headers),
                    MessageId       = messageIdFactory.Create().Create().ToString(),
                    MetaData        = meta,
                    CorrelationId   = m.MessageData.CorrelationId.ToString(),
                    TimeStamp       = unixTimeStampDelay,
                    ExpireTimeStamp = unixTimeStampExpiration,
                    Route           = m.MessageData.Route
                });
            });
            return(messagesToSend.ToList());
        }
        /// <inheritdoc />
        public async Task <string> Handle(SendMessageCommand commandSend)
        {
            TimeSpan?delay = null;
            //there are three possible locations for a message expiration. The user data and the header / internal headers
            //grab it from the internal header
            TimeSpan?expiration =
                commandSend.MessageToSend.GetInternalHeader(_headers.StandardHeaders.RpcTimeout).Timeout;

            //if the header value is zero, check the message expiration
            if (expiration == TimeSpan.Zero)
            {
                //try the message header
                expiration = commandSend.MessageToSend.GetHeader(_headers.StandardHeaders.RpcTimeout).Timeout;
            }

            //if the header value is zero, check the message expiration
            if (expiration == TimeSpan.Zero && commandSend.MessageData.GetExpiration().HasValue)
            {
                // ReSharper disable once PossibleInvalidOperationException
                expiration = commandSend.MessageData.GetExpiration().Value;
            }

            //treat a zero time as null
            if (expiration == TimeSpan.Zero)
            {
                expiration = null;
            }

            if (commandSend.MessageData.GetDelay().HasValue)
            {
                delay = commandSend.MessageData.GetDelay();
            }

            //determine which path to send the message on
            if (delay.HasValue && expiration.HasValue)
            {
                return
                    (await
                     SendDelayAndExpirationMessageAsync(commandSend,
                                                        _unixTimeFactory.Create().GetAddDifferenceMilliseconds(delay.Value),
                                                        _unixTimeFactory.Create().GetAddDifferenceMilliseconds(expiration.Value))
                     .ConfigureAwait(false));
            }
            if (delay.HasValue)
            {
                return
                    (await
                     SendDelayMessageAsync(commandSend,
                                           _unixTimeFactory.Create().GetAddDifferenceMilliseconds(delay.Value)).ConfigureAwait(false));
            }
            if (expiration.HasValue)
            {
                return
                    (await
                     SendExpirationMessageAsync(commandSend,
                                                _unixTimeFactory.Create().GetAddDifferenceMilliseconds(expiration.Value))
                     .ConfigureAwait(false));
            }
            return(await SendStandardMessageAsync(commandSend).ConfigureAwait(false));
        }
        /// <summary>
        /// Creates the messages to send.
        /// </summary>
        /// <param name="redisHeaders">The redis headers.</param>
        /// <param name="messages">The messages.</param>
        /// <param name="meta">The meta data, already serialized.</param>
        /// <param name="unixTimeFactory">The unix time factory.</param>
        /// <param name="messageIdFactory">The message identifier factory.</param>
        /// <param name="serializer">The composite serializer.</param>
        /// <returns></returns>
        public static List<EnqueueBatchLua.MessageToSend> CreateMessagesToSend(RedisHeaders redisHeaders, 
            IReadOnlyCollection<QueueMessage<IMessage, IAdditionalMessageData>> messages,
            byte[] meta, 
            IUnixTimeFactory unixTimeFactory,
            IGetMessageIdFactory messageIdFactory,
            ICompositeSerialization serializer)
        {
            var messagesToSend = new ConcurrentBag<EnqueueBatchLua.MessageToSend>();
            Parallel.ForEach(messages, m =>
            {
                //the correlation ID must be saved as a message header
                m.Message.SetHeader(redisHeaders.CorelationId, new RedisQueueCorrelationIdSerialized((Guid)m.MessageData.CorrelationId.Id.Value));

                //check for delay and expiration
                long unixTimeStampDelay = 0;
                long unixTimeStampExpiration = 0;
                if (m.MessageData.GetDelay().HasValue)
                {
                    // ReSharper disable once PossibleInvalidOperationException
                    unixTimeStampDelay = unixTimeFactory.Create().GetAddDifferenceMilliseconds(m.MessageData.GetDelay().Value);
                }
                // ReSharper disable once PossibleInvalidOperationException
                if (m.MessageData.GetExpiration().HasValue && m.MessageData.GetExpiration().Value != TimeSpan.Zero)
                {
                    var unixTime = unixTimeFactory.Create();
                    var timeSpan = m.MessageData.GetExpiration();
                    if (timeSpan != null)
                    {
                        var timespan = timeSpan.Value;
                        unixTimeStampExpiration = unixTime.GetAddDifferenceMilliseconds(timespan);
                    }
                }

                var serialized = serializer.Serializer.MessageToBytes(new MessageBody { Body = m.Message.Body });
                m.Message.SetHeader(redisHeaders.Headers.StandardHeaders.MessageInterceptorGraph, serialized.Graph);

                messagesToSend.Add(new EnqueueBatchLua.MessageToSend()
                {
                    Message = serialized.Output,
                    Headers = serializer.InternalSerializer.ConvertToBytes(m.Message.Headers),
                    MessageId = messageIdFactory.Create().Create().ToString(),
                    MetaData = meta,
                    CorrelationId = m.MessageData.CorrelationId.ToString(),
                    TimeStamp = unixTimeStampDelay,
                    ExpireTimeStamp = unixTimeStampExpiration
                });
            });
            return messagesToSend.ToList();
        }
Exemple #4
0
        /// <inheritdoc />
        public long Handle(SendHeartBeatCommand command)
        {
            var date = _unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds();

            _sendHeartbeatLua.Execute(command.QueueId.Id.Value.ToString(), date);
            return(date);
        }
Exemple #5
0
 /// <inheritdoc />
 public long Handle(MoveDelayedRecordsCommand command)
 {
     return(command.Token.IsCancellationRequested
         ? 0
         : _moveDelayedToPendingLua.Execute(_unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds(),
                                            _options.MoveDelayedMessagesBatchLimit, _rpcQueue));
 }
Exemple #6
0
 /// <summary>Initializes a new instance of the <see cref="DeleteMessageCommandHandler"/> class.</summary>
 /// <param name="errorLua">The error lua.</param>
 /// <param name="timeFactory">Time factory</param>
 public MoveRecordToErrorQueueCommandHandler(ErrorLua errorLua, IUnixTimeFactory timeFactory)
 {
     Guard.NotNull(() => errorLua, errorLua);
     Guard.NotNull(() => timeFactory, timeFactory);
     _errorLua = errorLua;
     _unixTime = timeFactory.Create();
 }
        /// <summary>
        /// Updates the heart beat for a record.
        /// </summary>
        /// <param name="context">The context.</param>
        public IHeartBeatStatus Send(IMessageContext context)
        {
            if (context.MessageId == null || !context.MessageId.HasValue)
            {
                return(null);
            }
            var unixTime = _sendHeartBeat.Handle(new SendHeartBeatCommand <string>(context.MessageId.Id.Value.ToString()));

            return(new HeartBeatStatus(context.MessageId, _unixTimeFactory.Create().DateTimeFromUnixTimestampMilliseconds(unixTime))); //UTC
        }
Exemple #8
0
 /// <inheritdoc />
 public void Handle(RollbackMessageCommand <string> command)
 {
     if (command.IncreaseQueueDelay.HasValue && command.IncreaseQueueDelay.Value != TimeSpan.Zero)
     {
         var unixTimestamp = _unixTimeFactory.Create().GetAddDifferenceMilliseconds(command.IncreaseQueueDelay.Value);
         _rollbackDelayLua.Execute(command.QueueId, unixTimestamp);
     }
     else
     {
         _rollbackLua.Execute(command.QueueId);
     }
 }
        /// <inheritdoc />
        public async Task <string> Handle(SendMessageCommand commandSend)
        {
            TimeSpan?delay      = null;
            TimeSpan?expiration = null;

            //check the message expiration
            if (commandSend.MessageData.GetExpiration().HasValue)
            {
                // ReSharper disable once PossibleInvalidOperationException
                expiration = commandSend.MessageData.GetExpiration().Value;
            }

            //treat a zero time as null
            if (expiration == TimeSpan.Zero)
            {
                expiration = null;
            }

            if (commandSend.MessageData.GetDelay().HasValue)
            {
                delay = commandSend.MessageData.GetDelay();
            }

            //determine which path to send the message on
            if (delay.HasValue && expiration.HasValue)
            {
                return
                    (await
                     SendDelayAndExpirationMessageAsync(commandSend,
                                                        _unixTimeFactory.Create().GetAddDifferenceMilliseconds(delay.Value),
                                                        _unixTimeFactory.Create().GetAddDifferenceMilliseconds(expiration.Value))
                     .ConfigureAwait(false));
            }
            if (delay.HasValue)
            {
                return
                    (await
                     SendDelayMessageAsync(commandSend,
                                           _unixTimeFactory.Create().GetAddDifferenceMilliseconds(delay.Value)).ConfigureAwait(false));
            }
            if (expiration.HasValue)
            {
                return
                    (await
                     SendExpirationMessageAsync(commandSend,
                                                _unixTimeFactory.Create().GetAddDifferenceMilliseconds(expiration.Value))
                     .ConfigureAwait(false));
            }
            return(await SendStandardMessageAsync(commandSend).ConfigureAwait(false));
        }
        /// <inheritdoc />
        public string Handle(SendMessageCommand commandSend)
        {
            TimeSpan?delay = null;
            //there are three possible locations for a message expiration. The user data and the header / internal headers
            //grab it from the internal header
            TimeSpan?expiration = TimeSpan.Zero;

            //check the message expiration
            if (commandSend.MessageData.GetExpiration().HasValue)
            {
                // ReSharper disable once PossibleInvalidOperationException
                expiration = commandSend.MessageData.GetExpiration().Value;
            }

            //treat a zero time as null
            if (expiration == TimeSpan.Zero)
            {
                expiration = null;
            }

            if (commandSend.MessageData.GetDelay().HasValue)
            {
                delay = commandSend.MessageData.GetDelay();
            }

            //determine which path to send the message on
            if (delay.HasValue && expiration.HasValue)
            {
                return(SendDelayAndExpirationMessage(commandSend,
                                                     _unixTimeFactory.Create().GetAddDifferenceMilliseconds(delay.Value),
                                                     _unixTimeFactory.Create().GetAddDifferenceMilliseconds(expiration.Value)));
            }
            if (delay.HasValue)
            {
                return(SendDelayMessage(commandSend, _unixTimeFactory.Create().GetAddDifferenceMilliseconds(delay.Value)));
            }
            if (expiration.HasValue)
            {
                return(SendExpirationMessage(commandSend,
                                             _unixTimeFactory.Create().GetAddDifferenceMilliseconds(expiration.Value)));
            }
            return(SendStandardMessage(commandSend));
        }
Exemple #11
0
        /// <inheritdoc />
        public QueueOutputMessages Handle(SendMessageCommandBatch commandSend)
        {
            var rc        = new ConcurrentBag <IQueueOutputMessage>();
            var splitList = commandSend.Messages.Partition(_sendBatchSize.BatchSize(commandSend.Messages.Count))
                            .Select(x => x.ToList())
                            .ToList();

            Parallel.ForEach(splitList, m =>
            {
                var meta =
                    _serializer.InternalSerializer.ConvertToBytes(
                        new RedisMetaData(_unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds()));
                foreach (var s in SendMessages(m, meta))
                {
                    rc.Add(s);
                }
            });
            return(new QueueOutputMessages(rc.ToList()));
        }
        /// <inheritdoc />
        public long Handle(SendHeartBeatCommand <string> command)
        {
            if (_connection.IsDisposed)
            {
                return(0);
            }

            if (string.IsNullOrWhiteSpace(command.QueueId))
            {
                return(0);
            }

            var db   = _connection.Connection.GetDatabase();
            var date = _unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds();

            db.SortedSetAdd(_redisNames.Working, command.QueueId, date, When.Exists);

            return(date);
        }
        /// <inheritdoc />
        public long Handle(SendHeartBeatCommand command)
        {
            if (_connection.IsDisposed)
            {
                return(0);
            }

            if (!command.QueueId.HasValue)
            {
                return(0);
            }

            var db   = _connection.Connection.GetDatabase();
            var date = _unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds();

            db.SortedSetAdd(_redisNames.Working, command.QueueId.Id.Value.ToString(), date, When.Exists);

            return(date);
        }
Exemple #14
0
        public List <string> Handle(GetErrorRecordsToDeleteQuery query)
        {
            var returnData = new List <string>();

            if (_connection.IsDisposed)
            {
                return(returnData);
            }

            var db        = _connection.Connection.GetDatabase();
            var timeStamp = _unixTime.Create().GetSubtractDifferenceMilliseconds(_errorConfiguration.MessageAge);
            var results   = db.SortedSetRangeByScore(_names.ErrorTime,
                                                     double.NegativeInfinity, timeStamp, Exclude.None,
                                                     Order.Descending, 0, _options.ClearErrorMessagesBatchLimit);

            foreach (var data in results)
            {
                returnData.Add(data);
            }

            return(returnData);
        }
        /// <inheritdoc />
        public RedisMessage Handle(ReceiveMessageQuery query)
        {
            byte[] message = null;
            byte[] headers = null;
            string messageId;
            var    poisonMessage = false;
            RedisQueueCorrelationIdSerialized correlationId = null;

            try
            {
                var          unixTimestamp = _unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds();
                RedisValue[] result;
                if (query.MessageId != null && query.MessageId.HasValue)
                {
                    result = _dequeueRpcLua.Execute(query.MessageId.Id.Value.ToString(), unixTimestamp);
                }
                else
                {
                    result = _dequeueLua.Execute(unixTimestamp);
                }

                if (result == null || result.Length == 1 && !result[0].HasValue || !result[0].HasValue)
                {
                    return(null);
                }

                if (!result[1].HasValue)
                {
                    //at this point, the record has been de-queued, but it can't be processed.
                    poisonMessage = true;
                }

                messageId = result[0];
                var id = new RedisQueueId(messageId);
                query.MessageContext.MessageId = id;
                if (!poisonMessage)
                {
                    message = result[1];
                    headers = result[2];
                    if (result[3].HasValue)
                    {
                        if (result[3].TryParse(out long messageExpiration))
                        {
                            if (messageExpiration - unixTimestamp < 0)
                            {
                                //message has expired
                                _deleteMessage.Handle(new DeleteMessageCommand(new RedisQueueId(messageId)));
                                return(new RedisMessage(messageId, null, true));
                            }
                        }
                    }
                }
            }
            catch (Exception error)
            {
                throw new ReceiveMessageException("Failed to dequeue a message", error);
            }

            if (poisonMessage)
            {
                //at this point, the record has been de-queued, but it can't be processed.
                throw new PoisonMessageException(
                          "An error has occurred trying to re-assemble a message de-queued from Redis; a messageId was returned, but the LUA script returned a null message. The message payload has most likely been lost.", null,
                          new RedisQueueId(messageId), new RedisQueueCorrelationId(Guid.Empty),
                          null, null);
            }

            try
            {
                var allHeaders = _serializer.InternalSerializer.ConvertBytesTo <IDictionary <string, object> > (headers);
                correlationId = (RedisQueueCorrelationIdSerialized)allHeaders[_redisHeaders.CorrelationId.Name];
                var messageGraph = (MessageInterceptorsGraph)allHeaders[_redisHeaders.Headers.StandardHeaders.MessageInterceptorGraph.Name];
                var messageData  = _serializer.Serializer.BytesToMessage <MessageBody>(message, messageGraph);

                var newMessage = _messageFactory.Create(messageData.Body, allHeaders);

                return(new RedisMessage(
                           messageId,
                           _receivedMessageFactory.Create(
                               newMessage,
                               new RedisQueueId(messageId),
                               new RedisQueueCorrelationId(correlationId.Id)), false));
            }
            catch (Exception error)
            {
                //at this point, the record has been de-queued, but it can't be processed.
                throw new PoisonMessageException(
                          "An error has occurred trying to re-assemble a message de-queued from redis", error,
                          new RedisQueueId(messageId), new RedisQueueCorrelationId(correlationId),
                          message, headers);
            }
        }
Exemple #16
0
        /// <inheritdoc />
        public async Task <QueueOutputMessages> Handle(SendMessageCommandBatch commandSend)
        {
            var rc        = new ConcurrentBag <IQueueOutputMessage>();
            var splitList = commandSend.Messages.Partition(_sendBatchSize.BatchSize(commandSend.Messages.Count))
                            .Select(x => x.ToList())
                            .ToList();

            foreach (var m in splitList)
            {
                var meta         = _serializer.InternalSerializer.ConvertToBytes(new RedisMetaData(_unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds()));
                var sentMessages = await SendMessagesAsync(m, meta).ConfigureAwait(false);

                foreach (var s in sentMessages)
                {
                    rc.Add(s);
                }
            }
            return(new QueueOutputMessages(rc.ToList()));
        }
 /// <inheritdoc />
 public IGetTime Create()
 {
     return(_unixTimeFactory.Create());
 }
 /// <inheritdoc />
 public List <ResetHeartBeatOutput> Handle(ResetHeartBeatCommand <string> command)
 {
     return(_resetHeartbeatLua.Execute(_unixTimeFactory.Create().GetSubtractDifferenceMilliseconds(_configuration.Time), _options.ResetHeartBeatBatchLimit));
 }
Exemple #19
0
 /// <inheritdoc />
 public long Handle(ClearExpiredMessagesCommand command)
 {
     return(_clearExpiredMessagesLua.Execute(_unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds(), _options.ClearExpiredMessagesBatchLimit));
 }
Exemple #20
0
 /// <inheritdoc />
 public long Handle(ResetHeartBeatCommand command)
 {
     return(_resetHeartbeatLua.Execute(_unixTimeFactory.Create().GetSubtractDifferenceMilliseconds(_configuration.Time), _options.ResetHeartBeatBatchLimit, _rpcQueue));
 }