/// <summary> /// Renews a lock on a message that makes it invisible from other receivers in /// the queue.This method is usually used to extend the message processing time. /// </summary> /// <param name="message">a message to extend its lock.</param> /// <param name="lockTimeout">a locking timeout in milliseconds.</param> public override async Task RenewLockAsync(MessageEnvelope message, long lockTimeout) { if (message.Reference == null) { return; } lock (_lock) { // Get message from locked queue LockedMessage lockedMessage = null; int lockedToken = (int)message.Reference; // If lock is found, extend the lock if (_lockedMessages.TryGetValue(lockedToken, out lockedMessage)) { // Todo: Shall we skip if the message already expired? if (lockedMessage.ExpirationTimeUtc > DateTime.UtcNow) { lockedMessage.ExpirationTimeUtc = DateTime.UtcNow.Add(lockedMessage.Timeout); } } } _logger.Trace(message.CorrelationId, "Renewed lock for message {0} at {1}", message, this); await Task.Delay(0); }
/// <summary> /// Receives an incoming message and removes it from the queue. /// </summary> /// <param name="correlationId">(optional) transaction id to trace execution through call chain.</param> /// <param name="waitTimeout">a timeout in milliseconds to wait for a message to come.</param> /// <returns>a message envelop object.</returns> public override async Task <MessageEnvelope> ReceiveAsync(string correlationId, long waitTimeout) { await Task.Delay(0); lock (_lock) { if (_messages.Count == 0) { _receiveEvent.Reset(); } else { _receiveEvent.Set(); } } _receiveEvent.WaitOne(TimeSpan.FromMilliseconds(waitTimeout)); MessageEnvelope message = null; lock (_lock) { if (_messages.Count == 0) { return(null); } // Get message the the queue message = _messages.Dequeue(); if (message != null) { // Generate and set locked token var lockedToken = _lockTokenSequence++; message.Reference = lockedToken; // Add messages to locked messages list var lockedMessage = new LockedMessage { ExpirationTimeUtc = DateTime.UtcNow.AddMilliseconds(waitTimeout), Message = message, Timeout = TimeSpan.FromMilliseconds(waitTimeout) }; _lockedMessages.Add(lockedToken, lockedMessage); } } if (message != null) { _counters.IncrementOne("queue." + Name + ".received_messages"); _logger.Debug(message.CorrelationId, "Received message {0} via {1}", message, this); } return(message); }
/// <summary> /// Returns message into the queue and makes it available for all subscribers to /// receive it again.This method is usually used to return a message which could /// not be processed at the moment to repeat the attempt.Messages that cause /// unrecoverable errors shall be removed permanently or/and send to dead letter queue. /// </summary> /// <param name="message">a message to return.</param> public override async Task AbandonAsync(MessageEnvelope message) { if (message.Reference == null) { return; } lock (_lock) { // Get message from locked queue int lockedToken = (int)message.Reference; LockedMessage lockedMessage = null; if (_lockedMessages.TryGetValue(lockedToken, out lockedMessage)) { // Remove from locked messages _lockedMessages.Remove(lockedToken); message.Reference = null; // Skip if it is already expired if (lockedMessage.ExpirationTimeUtc <= DateTime.UtcNow) { return; } } // Skip if it absent else { return; } } _logger.Trace(message.CorrelationId, "Abandoned message {0} at {1}", message, this); // Add back to the queue await SendAsync(message.CorrelationId, message); }