Azure Durable Function Service Bus Trigger - Peeklock not renewed

Arin Roy 11 Reputation points

In my attempt to implement a Service Bus trigger on a Durable Client function, it has come to my notice that if the message is not handled within the lock duration, the function runtime does not renew the peek lock - which is the case with standard functions. I assume it is due to the fact that the client function where the trigger is attached already completes before the orchestrator can complete all activities. However, for complex orchestrations where the state of the message might be tied to the outcome of the activities, how do we manage the messages? Is there a recommended pattern to handle this in Durable Functions.
Right now the behavior is:

  1. Client function triggered.
  2. Orchestration started for trigger 1
  3. Client Function completed.
  4. Peek lock expires
  5. Client Function re-triggered with incremented delivery count
  6. Orchestration started for trigger 2
  7. Orchestration ended for trigger 1
    and so on......

While the behavior in terms of how service bus retries with incremented delivery count on lock expiration makes sense, that the Durable Extension cannot handle the lock renewal is sort of a let down.

***I should mention that I have in my host.json set autoComplete to false for messageHandlerOptions. This is because I want to handle the message in the orchestrator based on the outcome of the activity functions. If I do allow autocomplete, then the message is completed automatically(as expected) when the client function ends. However, that is not the desired outcome for me.

Azure Service Bus
Azure Service Bus
An Azure service that provides cloud messaging as a service and hybrid integration.
587 questions
Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
4,622 questions
{count} vote

1 answer

Sort by: Most helpful
  1. Pramod Valavala 20,611 Reputation points Microsoft Employee

    That is the expected behavior. The client function that is triggered is no longer running and hence the lock is not held.

    You can design around this behavior in a couple of ways I suppose

    1. Separate Message for Completion/Failure
    Instead of holding the message lock, you can complete it and once the orchestration completes, push a message to mark the completion (or failure).

    2. Message Deferral
    While this feature may not have been designed for this use case, you could leverage this to your cause.

    The client function would start a new instance of the orchestrator, passing the sequence number of the message so that it can be retrieved later (by another activity function at the end or on failure) and defer the message so that it won't be processed again.