none
Azure service bus subscription: How do I delete the message when I receive a MessageLockLostException? RRS feed

  • Question

  • Hi,

    We are receiving a MessageLockLostException when we try to execute

    brokeredMessage.Complete();

    on a message received by a subscription. I checked for possible causes for this and came up with information here which states that the lock duration on a subscription cannot be set. If a process is unable to complete a message within 5 minutes, then the lock is released.

    My requirement is that if I have reached till "brokeredMessage.Complete();" then I have essentially finished processing a message and my worker should not process it again.

    Is there any way this can be achieved? Say I catch the MessageLockLost exception, is there a way to delete the message from the subscription? I also read something about renewing the lock here, but that pertains to a service bus queue. Can I do something similar to this without spawning another thread?

    Thanks,

    Nikhil

    Friday, December 26, 2014 11:01 AM

Answers

  • Hi Nikhil,

    Use following code to renew the message lock in case of lock time expiration and acquire the lock to delete the message(message.Complete()) or move to deadletter queue(message.Deadletter())

    //Create a CTS to launch a task in charge of renewing the message lock
    var brokeredMessageRenewCancellationTokenSource = new CancellationTokenSource();
     
    try
    {
        var brokeredMessage = _client.Receive();
     
        var brokeredMessageRenew = Task.Factory.StartNew(() =>
        {
            while (!brokeredMessageRenewCancellationTokenSource.Token.IsCancellationRequested)
            {
                //Based on LockedUntilUtc property to determine if the lock expires soon
                if (DateTime.UtcNow > brokeredMessage.LockedUntilUtc.AddSeconds(-10))
                {
                    // If so, we repeat the message
                    brokeredMessage.RenewLock();
                }
         
                Thread.Sleep(500);
            }
        }, brokeredMessageRenewCancellationTokenSource.Token);
     
        // Performing a lengthy operation
        RunLongRunningOperation();
         
        // We mark the message as completed
        brokeredMessage.Complete();
    }
    catch(MessageLockLostException)
    {
        // lock expired
    }
    catch(Exception)
    {    
        brokeredMessage.Abandon();
    }
    finally
    {
        // Lock is stopped renewing task
        brokeredMessageRenewCancellationTokenSource.Cancel();
    }


    Thanks Subhendu DE - DotNet Artisan If a post answers your question, please click Mark As Answer on that post. If you find a post helpful, please click Vote as Helpful


    Wednesday, December 31, 2014 3:44 AM
  • Hi Nikhil,

    Deadlettering a message also requires owning the lock first where the client might have already lost it. The client which is processing the message needs to make sure the lock doesn't expire if processing needs to be atomic and there's no rollback capability. If the processing of a particular message is taking longer I suggest you to implement RenewLock into your clients. See the MSDN reference below:

    http://msdn.microsoft.com/en-us/library/microsoft.servicebus.messaging.brokeredmessage.renewlock.aspx

    Please note that PeekLock mode is all about setting your message back to available state once one of your client fails to process it. You may also consider ReceiveAndDelete mode to avoid double processing but in this case you may loose the message if processing client crashes or it cannot recover from a fatal failure.

    Let me know if you have any questions around this.

    • Marked as answer by Nikhil Bhawkar Wednesday, December 31, 2014 4:23 AM
    Tuesday, December 30, 2014 11:27 PM

All replies

  • What's the LockDuration value for the subscription? If you haven't specified it the default value is 60 seconds. After the lock duration expires any operation on a locked message will throw MessageLockLostException. Lock expired messages become available for the next receive.

    You can renew a lock on subscription as well. If you fail to renew the lock and get MessageLockLostException on Complete call then you better rollback your changes and expect to process the same message again on either the same role or any other role receiving from the same subscription.

    Friday, December 26, 2014 7:20 PM
  • Hi Serkant,

    Thanks for your reply. I agree with your point that once the lock expires, the message becomes available for processing. You suggest that I should roll back the changes in case I get a MessageLostException. However, what if the action cannot be rolled back. i.e. say I send an SMS based on the BrokeredMessage, that cannot be rolled back.

    In such cases, would it not me more appropriate to dead-letter the message only for the MessageLockException with the appropriate reason added?

    Saturday, December 27, 2014 2:03 PM
  • Hi Nikhil,

    Deadlettering a message also requires owning the lock first where the client might have already lost it. The client which is processing the message needs to make sure the lock doesn't expire if processing needs to be atomic and there's no rollback capability. If the processing of a particular message is taking longer I suggest you to implement RenewLock into your clients. See the MSDN reference below:

    http://msdn.microsoft.com/en-us/library/microsoft.servicebus.messaging.brokeredmessage.renewlock.aspx

    Please note that PeekLock mode is all about setting your message back to available state once one of your client fails to process it. You may also consider ReceiveAndDelete mode to avoid double processing but in this case you may loose the message if processing client crashes or it cannot recover from a fatal failure.

    Let me know if you have any questions around this.

    • Marked as answer by Nikhil Bhawkar Wednesday, December 31, 2014 4:23 AM
    Tuesday, December 30, 2014 11:27 PM
  • Hi Nikhil,

    Use following code to renew the message lock in case of lock time expiration and acquire the lock to delete the message(message.Complete()) or move to deadletter queue(message.Deadletter())

    //Create a CTS to launch a task in charge of renewing the message lock
    var brokeredMessageRenewCancellationTokenSource = new CancellationTokenSource();
     
    try
    {
        var brokeredMessage = _client.Receive();
     
        var brokeredMessageRenew = Task.Factory.StartNew(() =>
        {
            while (!brokeredMessageRenewCancellationTokenSource.Token.IsCancellationRequested)
            {
                //Based on LockedUntilUtc property to determine if the lock expires soon
                if (DateTime.UtcNow > brokeredMessage.LockedUntilUtc.AddSeconds(-10))
                {
                    // If so, we repeat the message
                    brokeredMessage.RenewLock();
                }
         
                Thread.Sleep(500);
            }
        }, brokeredMessageRenewCancellationTokenSource.Token);
     
        // Performing a lengthy operation
        RunLongRunningOperation();
         
        // We mark the message as completed
        brokeredMessage.Complete();
    }
    catch(MessageLockLostException)
    {
        // lock expired
    }
    catch(Exception)
    {    
        brokeredMessage.Abandon();
    }
    finally
    {
        // Lock is stopped renewing task
        brokeredMessageRenewCancellationTokenSource.Cancel();
    }


    Thanks Subhendu DE - DotNet Artisan If a post answers your question, please click Mark As Answer on that post. If you find a post helpful, please click Vote as Helpful


    Wednesday, December 31, 2014 3:44 AM
  • Thanks Subhendu,

    Your detailed code helps a lot.

    Regards,

    Nikhil

    Wednesday, December 31, 2014 4:25 AM