Azure Service Bus BrokeredMessage has already been consumed? - azure

I'm having an intermittent problem with the Azure Service bus. Sporadically, placing a message on the bus causes the following exception:
TYPE: InvalidOperationException
MESSAGE: The operation cannot be performed because the brokered message '723eab13dab34351a78bb687d0923b89' has already been consumed. Please use a new BrokeredMessage instance for the operation.
STACKTRACE
at Microsoft.ServiceBus.Messaging.MessagingUtilities.ValidateAndSetConsumedMessages(IEnumerable`1 messages)
at Microsoft.ServiceBus.Messaging.MessageSender.Send(TrackingContext trackingContext, IEnumerable`1 messages, TimeSpan timeout)
at Microsoft.Practices.TransientFaultHandling.RetryPolicy.<>c__DisplayClass1.<ExecuteAction>b__0()
at Microsoft.Practices.TransientFaultHandling.RetryPolicy.ExecuteAction[TResult](Func`1 func)
at IQ.IR.Core.ServiceBus.AzureBus`1.Enqueue(T message) in c:\BuildAgent\work\cc0c51104c02a4e9\IQ.IR.Core\ServiceBus\AzureBus.cs:line 69
...Rest of stacktrace snipped as it's within my app
The offending code from AzureBus is:
public void Enqueue(T message)
{
using (var brokeredMessage = new BrokeredMessage(message) { Label = message.GetType().FullName, TimeToLive = _timeToLive })
{
_retryPolicy.ExecuteAction(() => _sender.Send(brokeredMessage));
}
}
Where T message being passed in is
[Serializable]
public class ValidationMessage
{
public string ValidationToken { get; set;}
}
And _retryPolicy is a
RetryPolicy<ServiceBusTransientErrorDetectionStrategy>
_timeToLive is a 12 hour timespan
Any ideas?

.... and to pile on to Abhishek's answer: Right now you need to construct a new BrokeredMessage for each retry, so your retry policy scope needs to be one level further up. Mind that if you put in a stream, we will use that stream as-is inside the brokered message and pull straight fro it onto the wire, so you will need to make copies of the stream ahead of time for a retry loop.

The error indicates that the message was "already sent" but an error occurred in the process. Unfortunately there is no easy way to know this by inspecting the message and the message cannot be reused again as it is considered consumed. We are working on some improvements such as allowing you to query the state of such a message and throwing a MessagingException instead of InvalidOperation. Finally the ability to clone a message will help to make recovery easier from such failures.

I recently ran into this and found another cause: if you are constructing a BrokeredMessage and set a break point prior to sending it with your MessageSender, and inspect the properties on the Message, it will attempt to access the Queue and throw this exception. Simply sending the message first without inspecting its properties in the IDE will not cause this problem.

Is it possible that the message could have been sent, even though there was an error? Should the message be idempotent before a retry is attempted in this case?

Related

how to cleanly shutdown high-concurrency Jms.messageDrivenChannelAdapter?

When I try to shutdown my spring-integration process, the flow using an inbound Jms.messageDrivenChannelAdapter throws the following error message:
"org.springframework.jms.listener.DefaultMessageListenerContainer - Rejecting received message because of the listener container been stopeed in the meantime"
my inbound adapter is defined as follows:
Jms.messageDrivenChannelAdapter(
Jms.container(jmsConnectionFactory, destinationName)
.concurrency(highConcurrency)
.get()
)
I believe that my problem is that the default "receiveTimeout" on my jms container is too small and that I need to increase that value to cater for my "high-concurrency" (right ?), as "receiveTimeout" seems to be the only value the container "doShutdown" method cares about.
Now, the sourceCode for the receiveTimeout property says "this value needs to be smaller than the transaction timeout". Also the spring-integration doco regarding inbound jms adapters says "if you want the entire flow to be transactional [...] consider using a jms-message-driven-channel-adapter with acknowledge set to transacted (the default)", which seems to imply that the jms adapter is transactional by default.
Hence, my main question is: even though I'm not using any explicit transaction manager, do I need to not only explicitely set "receiveTimeout" on my container but also "transactionTimeout" with transactionTimeout > receiveTimeout ?
Thanks a lot in advance for your expertise and your time.
Best Regards
That is not "throws". That is just warn:
protected void doExecuteListener(Session session, Message message) throws JMSException {
if (!isAcceptMessagesWhileStopping() && !isRunning()) {
if (logger.isWarnEnabled()) {
logger.warn("Rejecting received message because of the listener container " +
"having been stopped in the meantime: " + message);
}
rollbackIfNecessary(session);
throw new MessageRejectedWhileStoppingException();
}
And pay attention to that rollbackIfNecessary(session);. So, even if the received message slips somehow into this listener function, the whole environment makes it sure that the state is not broken and the data is not lost - the session is rolled back.
The transactionTimeout does not make sense if you don't use a transactionManager. Spring Integration makes it transacted exactly for the use-case we see around that warn log.

How to re-queue message with updated information while working with Azure Service Bus Queue Function?

While working with Azure Service Bus Queue function, we know that whenever there is an exception, azure function will perform a default retry policy (max count = 10), what we would like to do is to have our message with a property called retryCount, so when exception generates, we would increase the retryCount += 1, and also add the current exception to our message, then next time while function performs the retry, we could know this is the xth time that it comes in along with x records of exceptions. We know that the Message object had a read-only property called deliveryCount, however, we cannot bind our addition information or figure out what would be the reason of last failed delivery from the Message object.
However, after we tried to implement our idea, we found that whenever the function performs the retry, it always reload the initial message from the queue, not with our updated message. Is there any way to let it retry with updated message without force to re-send the updated back to the current queue?
In addition, how could we customize the current retry logic, for example, decrease the max retry count from 10 to 1 and use Polly to handle some scenario inside the function?
You don't really need a custom retryCount as the message already contains a system property called DeliveryCount that tracks the number of delivery (read processing) attempts. If you need to store some additional metadata between the retries, you would need to abandon your message. With Functions v2, to abandon a message you will need to use the message receiver used to receive the message.
public static async Task ProcessMessage([ServiceBusTrigger("myqueue")] string message,
int deliveryCount,
MessageReceiver messageReceiver,
string lockToken)
{
//
await messageReceiver.AbandonAsync(lockToken,
new Dictionary<string, object> { { "Reason", "Blah" });
}
Note that to ensure Azure Functions continues to process the message you will need to throw an exception. Otherwise, Functions by default assumes the message was processed successfully and will attempt to complete the message.

QueueTrigger Attribute Visibility Timeout

If I were to get a message from queue using Azure.Storage.Queue
queue.GetMessage(TimeSpan.FromMinutes(20));
I can set the visibility timeout, however when trying to use Azure.WebJobs (SDK 0.4.0-beta) attributes to auto bind a webjob to a queue
i.e.
public static void ProcessQueueMessage([QueueTrigger("myqueue")] string message){
//do something with queue item
}
Is there a way to set the visibility timeout on the attribute? There does not seem to be an option in JobHostConfiguration().Queues. If there is no way to override, is it the standard 30 seconds then?
In the latest v1.1.0 release, you can now control the visibility timeout by registering your own custom QueueProcessor instances via JobHostConfiguration.Queues.QueueProcessorFactory. This allows you to control advanced message processing behavior globally or per queue/function.
For example, to set the visibility for failed messages, you can override ReleaseMessageAsync as follows:
protected override async Task ReleaseMessageAsync(CloudQueueMessage message, FunctionResult result, TimeSpan visibilityTimeout, CancellationToken cancellationToken)
{
// demonstrates how visibility timeout for failed messages can be customized
// the logic here could implement exponential backoff, etc.
visibilityTimeout = TimeSpan.FromSeconds(message.DequeueCount);
await base.ReleaseMessageAsync(message, result, visibilityTimeout, cancellationToken);
}
More details can be found in the release notes here.
I have the same question and haven't found answer yet. But, to answer a part of your question, the default lease is 10 minutes.
Quoting the Azure Website: "When the method completes, the queue message is deleted. If the method fails before completing, the queue message is not deleted; after a 10-minute lease expires, the message is released to be picked up again and processed. This sequence won't be repeated indefinitely if a message always causes an exception. After 5 unsuccessful attempts to process a message, the message is moved to a queue named {queuename}-poison. The maximum number of attempts is configurable."
Link: http://azure.microsoft.com/en-us/documentation/articles/websites-dotnet-webjobs-sdk-get-started/
Section: ContosoAdsWebJob - Functions.cs - GenerateThumbnail method
Hope this helps!

Can the Azure Service Bus be delayed before retrying a message?

The Azure Service Bus supports a built-in retry mechanism which makes an abandoned message immediately visible for another read attempt. I'm trying to use this mechanism to handle some transient errors, but the message is made available immediately after being abandoned.
What I would like to do is make the message invisible for a period of time after it is abandoned, preferably based on an exponentially incrementing policy.
I've tried to set the ScheduledEnqueueTimeUtc property when abandoning the message, but it doesn't seem to have an effect:
var messagingFactory = MessagingFactory.CreateFromConnectionString(...);
var receiver = messagingFactory.CreateMessageReceiver("test-queue");
receiver.OnMessageAsync(async brokeredMessage =>
{
await brokeredMessage.AbandonAsync(
new Dictionary<string, object>
{
{ "ScheduledEnqueueTimeUtc", DateTime.UtcNow.AddSeconds(30) }
});
}
});
I've considered not abandoning the message at all and just letting the lock expire, but this would require having some way to influence how the MessageReceiver specifies the lock duration on a message, and I can't find anything in the API to let me change this value. In addition, it wouldn't be possible to read the delivery count of the message (and therefore make a decision for how long to wait for the next retry) until after the lock is already required.
Can the retry policy in the Message Bus be influenced in some way, or can a delay be artificially introduced in some other way?
Careful here because I think you are confusing the retry feature with the automatic Complete/Abandon mechanism for the OnMessage event-driven message handling. The built in retry mechanism comes into play when a call to the Service Bus fails. For example, if you call to set a message as complete and that fails, then the retry mechanism would kick in. If you are processing a message an exception occurs in your own code that will NOT trigger a retry through the retry feature. Your question doesn't get explicit on if the error is from your code or when attempting to contact the service bus.
If you are indeed after modifying the retry policy that occurs when an error occurs attempting to communicate with the service bus you can modify the RetryPolicy that is set on the MessageReciver itself. There is an RetryExponitial which is used by default, as well as an abstract RetryPolicy you can create your own from.
What I think you are after is more control over what happens when you get an exception doing your processing, and you want to push off working on that message. There are a few options:
When you create your message handler you can set up OnMessageOptions. One of the properties is "AutoComplete". By default this is set to true, which means as soon as processing for the message is completed the Complete method is called automatically. If an exception occurs then abandon is automatically called, which is what you are seeing. By setting the AutoComplete to false you required to call Complete on your own from within the message handler. Failing to do so will cause the message lock to eventually run out, which is one of the behaviors you are looking for.
So, you could write your handler so that if an exception occurs during your processing you simply do not call Complete. The message would then remain on the queue until it's lock runs out and then would become available again. The standard dead lettering mechanism applies and after x number of tries it will be put into the deadletter queue automatically.
A caution of handling this way is that any type of exception will be treated this way. You really need to think about what types of exceptions are doing this and if you really want to push off processing or not. For example, if you are calling a third party system during your processing and it gives you an exception you know is transient, great. If, however, it gives you an error that you know will be a big problem then you may decide to do something else in the system besides just bailing on the message.
You could also look at the "Defer" method. This method actually will then not allow that message to be processed off the queue unless it is specifically pulled by its sequence number. You're code would have to remember the sequence number value and pull it. This isn't quite what you described though.
Another option is you can move away from the OnMessage, Event-driven style of processing messages. While this is very helpful you don't get a lot of control over things. Instead hook up your own processing loop and handle the abandon/complete on your own. You'll also need to deal some of the threading/concurrent call management that the OnMessage pattern gives you. This can be more work but you have the ultimate in flexibility.
Finally, I believe the reason the call you made to AbandonAsync passing the properties you wanted to modify didn't work is that those properties are referring to Metadata properties on the method, not standard properties on BrokeredMessage.
I actually asked this same question last year (implementation aside) with the three approaches I could think of looking at the API. #ClemensVasters, who works on the SB team, responded that using Defer with some kind of re-receive is really the only way to control this precisely.
You can read my comment to his answer for a specific approach to doing it where I suggest using a secondary queue to store messages that indicate which primary messages have been deferred and need to be re-received from the main queue. Then you can control how long you wait by setting the ScheduledEnqueueTimeUtc on those secondary messages to control exactly how long you wait before you retry.
I ran into a similar issue where our order picking system is legacy and goes into maintenance mode each night.
Using the ideas in this article(https://markheath.net/post/defer-processing-azure-service-bus-message) I created a custom property to track how many times a message has been resubmitted and manually dead lettering the message after 10 tries. If the message is under 10 retries it clones the message increments the custom property and sets the en queue of the new message.
using Microsoft.Azure.ServiceBus;
public PickQueue()
{
queueClient = new QueueClient(QUEUE_CONN_STRING, QUEUE_NAME);
}
public async Task QueueMessageAsync(int OrderId)
{
string body = JsonConvert.SerializeObject(OrderId);
var message = new Message(Encoding.UTF8.GetBytes(body));
await queueClient.SendAsync(message);
}
public async Task ReQueueMessageAsync(Message message, DateTime utcEnqueueTime)
{
int resubmitCount = (int)(message.UserProperties["ResubmitCount"] ?? 0) + 1;
if (resubmitCount > 10)
{
await queueClient.DeadLetterAsync(message.SystemProperties.LockToken);
}
else
{
Message clone = message.Clone();
clone.UserProperties["ResubmitCount"] = ++resubmitCount;
await queueClient.ScheduleMessageAsync(message, utcEnqueueTime);
}
}
This question asks how to implement exponential backoff in Azure Functions. If you do not want to use the built-in RetryPolicy (only available when autoComplete = false), here's the solution I've been using:
public static async Task ExceptionHandler(IMessageSession MessageSession, string LockToken, int DeliveryCount)
{
if (DeliveryCount < Globals.MaxDeliveryCount)
{
var DelaySeconds = Math.Pow(Globals.ExponentialBackoff, DeliveryCount);
await Task.Delay(TimeSpan.FromSeconds(DelaySeconds));
await MessageSession.AbandonAsync(LockToken);
}
else
{
await MessageSession.DeadLetterAsync(LockToken);
}
}

An aggregator that can release when all records are processed, even with errors

I am building a system with Spring Integration that processes all lines in a file as records. Because some of the String records are malformed I have multiple paths through the application via a Splitter and Aggregator combination (I'm building the Aggregator as we speak).
Further, some of the records are so malformed that they are effectively errors. However I have a requirement that all records must be processed therefore I must identify and log gross malformation errors separately and finish processing the file. In other words, I can not fail to process the file but instead must only log errors.
Aggregator
I intend to do achieve the goal of processing grossly malformed records by modifying the headers on the incoming message and passing the message on-ward to the Aggregator which can search for the existence of such a parameter. I'll effectively be hand coding in some error handling situations to my processors and aggregator.
My Release Strategy for the Aggregator will be when all messages are processed.
Code Extract
This code comes from a blog entry by Matt Vickery. He constructs an entirely new message (using MessageBuilder and transferring headers) whereas I will just add something to the Message headers. He includes this code in a gateway which subsequently transfers the Message onto the Aggregator.
public Message<AvsResponse> service(Message<AvsRequest> message) {
Assert.notNull(message, MISSING_MANDATORY_ARG);
Assert.notNull(message.getPayload(), MISSING_MANDATORY_ARG);
MessageHeaders requestMessageHeaders = message.getHeaders();
Message<AvsResponse> responseMessage = null;
try {
logger.debug("Entering AVS Gateway");
responseMessage = avsGateway.send(message);
if (responseMessage == null)
responseMessage = buildNewResponse(requestMessageHeaders,
AvsResponseType.NULL_RESULT);
logger.debug("Exited AVS Gateway");
return responseMessage;
}
catch (Exception e) {
return buildNewResponse(responseMessage, requestMessageHeaders,
AvsResponseType.EXCEPTION_RESULT, e);
}
}
Confusion (...at least, that which I know about)
My questions are as follows:
When I have such a release strategy (all messages processed), is that the best way to ensure all messages get through to the Aggregator?
When using an Aggregator it seems like in practical cases, it would be very common to need access to the Message in some previous step, as opposed to just passing and processing simple POJOs. Would that be true or is there something I should be doing to simplify my design so I can avoid Message
I came across a blog entry by Matt Vickery showing how he achieves what seems to be similar with an Aggregator. I'm using his work as a guide.
P.S. Per Artem Bilan's advice, I'm avoiding creating my own messages and letting SI turn them into Messages
There is no difference for Aggregator if payload is valid or not. Its general purpose is to build a List (by default) of payloads to one Message. And it does it via some sequenceDetails from MessageHeaders. It is first.
If you use Splitter, it is responsible to enrich each produced Message with default sequenceDetails. So, if you have this configuration:
<splitter/>
<aggregator/>
And if your inbound payload is List, you end up with List after aggregator as well.
I assume, that your Splitter just produces String payloads from File lines.
Then you pass each Message to some service/transformer.
The result of that you may pass to the Aggregator.
But as you say some of payloads are not valid and your processor fails with an Exception.
So, how about just try...catch within that POJO method and return some payload with error indicator, e.g. simple String "Oops!".
As I described before: the result of POJO method will be pushed to payload of the Message by Framework. And what is magic, that sequenceDetails will be there in the MessageHeaders too.
I don't see reason to write some custom ReleaseStrategy for this task, or even any other Aggregator's strategies...
Let me know, what you don't understand.
UPDATE
To add some error-indicator to message headers and don't throw Exception, it really will be simpler to build a new Message from code, not via some error-channel flow:
try {
return [GOOD_RESULT];
}
catch(Exception e) {
return MessageBuilder.withPayload(payload).setHeader("ERROR", e.getMessage()).build();
}
But in this case you should use <service-activator> instead of <transformer>, because the last one doesn't copy headers from inbound Message. And you really need them - setHeader for aggregator.

Resources