async Task DeleteMessage(SqsReceivedDelayedMessage messageToDeleteWithAnotherAttempt) { try { // should not be cancelled await sqsClient.DeleteMessageAsync(messageToDeleteWithAnotherAttempt.QueueUrl, messageToDeleteWithAnotherAttempt.ReceiptHandle).ConfigureAwait(false); } catch (ReceiptHandleIsInvalidException ex) { Logger.Info($"Message receipt handle '{messageToDeleteWithAnotherAttempt.ReceiptHandle}' no longer valid.", ex); } }
IReadOnlyCollection <SqsReceivedDelayedMessage> PrepareMessages(CancellationToken token, ReceiveMessageResponse receivedMessages, TimeSpan clockCorrection) { List <SqsReceivedDelayedMessage> preparedMessages = null; foreach (var receivedMessage in receivedMessages.Messages) { token.ThrowIfCancellationRequested(); preparedMessages = preparedMessages ?? new List <SqsReceivedDelayedMessage>(receivedMessages.Messages.Count); long delaySeconds = 0; if (receivedMessage.MessageAttributes.TryGetValue(TransportHeaders.DelaySeconds, out var delayAttribute)) { long.TryParse(delayAttribute.StringValue, out delaySeconds); } string originalMessageId = null; if (receivedMessage.MessageAttributes.TryGetValue(Headers.MessageId, out var messageIdAttribute)) { originalMessageId = messageIdAttribute.StringValue; } var sent = receivedMessage.GetAdjustedDateTimeFromServerSetAttributes("SentTimestamp", clockCorrection); var received = receivedMessage.GetAdjustedDateTimeFromServerSetAttributes("ApproximateFirstReceiveTimestamp", clockCorrection); if (Convert.ToInt32(receivedMessage.Attributes["ApproximateReceiveCount"]) > 1) { received = DateTime.UtcNow; } var elapsed = received - sent; var remainingDelay = delaySeconds - (long)elapsed.TotalSeconds; SqsReceivedDelayedMessage preparedMessage; if (remainingDelay > configuration.DelayedDeliveryQueueDelayTime) { preparedMessage = new SqsReceivedDelayedMessage(originalMessageId, receivedMessage.ReceiptHandle) { QueueUrl = delayedDeliveryQueueUrl, MessageAttributes = { [TransportHeaders.DelaySeconds] = new MessageAttributeValue { StringValue = remainingDelay.ToString(), DataType = "String" } } }; var deduplicationId = receivedMessage.Attributes["MessageDeduplicationId"]; // this is only here for acceptance testing purpose. In real prod code this is always false. // it allows us to fake multiple cycles over the FIFO queue without being subjected to deduplication if (configuration.DelayedDeliveryQueueDelayTime < TransportConfiguration.AwsMaximumQueueDelayTime) { deduplicationId = Guid.NewGuid().ToString(); } preparedMessage.MessageDeduplicationId = preparedMessage.MessageGroupId = deduplicationId; } else { preparedMessage = new SqsReceivedDelayedMessage(originalMessageId, receivedMessage.ReceiptHandle) { QueueUrl = inputQueueUrl }; if (remainingDelay > 0) { preparedMessage.DelaySeconds = Convert.ToInt32(remainingDelay); } } if (string.IsNullOrEmpty(originalMessageId)) { // for backward compatibility if we couldn't fetch the message id header from the attributes we use the message deduplication id originalMessageId = receivedMessage.Attributes["MessageDeduplicationId"]; } // because message attributes are part of the content size restriction we want to prevent message size from changing thus we add it // for native delayed deliver as well preparedMessage.MessageAttributes[Headers.MessageId] = new MessageAttributeValue { StringValue = originalMessageId, DataType = "String" }; preparedMessage.Body = receivedMessage.Body; preparedMessage.CalculateSize(); preparedMessages.Add(preparedMessage); } return(preparedMessages); }