/// <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(); }
/// <inheritdoc /> public long Handle(SendHeartBeatCommand command) { var date = _unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds(); _sendHeartbeatLua.Execute(command.QueueId.Id.Value.ToString(), date); return(date); }
/// <inheritdoc /> public long Handle(MoveDelayedRecordsCommand command) { return(command.Token.IsCancellationRequested ? 0 : _moveDelayedToPendingLua.Execute(_unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds(), _options.MoveDelayedMessagesBatchLimit, _rpcQueue)); }
/// <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 }
/// <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)); }
/// <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); }
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); } }
/// <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)); }
/// <inheritdoc /> public long Handle(ClearExpiredMessagesCommand command) { return(_clearExpiredMessagesLua.Execute(_unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds(), _options.ClearExpiredMessagesBatchLimit)); }
/// <inheritdoc /> public long Handle(ResetHeartBeatCommand command) { return(_resetHeartbeatLua.Execute(_unixTimeFactory.Create().GetSubtractDifferenceMilliseconds(_configuration.Time), _options.ResetHeartBeatBatchLimit, _rpcQueue)); }