I am using Azure Function Service Bus Queue Trigger binding to retry my service if there is any exception been thrown.
I have the following in the host.json
"extensions": {
"serviceBus": {
"messageHandlerOptions": {
"autoComplete": false
}
}
}
My package reference
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.15.0" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.5.1" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.ServiceBus" Version="4.3.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="3.1.20" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.13" />
</ItemGroup>
But keep getting
Microsoft.Azure.ServiceBus: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue, or was received by a different receiver instance.
My Azure Function method
public async Task Run([ServiceBusTrigger("subprocess", Connection = "sb")] Message message,
MessageReceiver messageReceiver,
[ServiceBus("subprocess", Connection = "sb")] MessageSender sender,
ILogger log)
Here is the complete code
public class BozaSubProcessServiceBusQueueTrigger
{
private const string RetryCountUserProperty = "retry-count";
private const string SubProcessException = "SubProcessException";
private const string OriginalSequenceNumber = "original-SequenceNumber";
private static readonly int RetryCount = 5;
private readonly BozaSubProcessFactory accountTransferProcessFactory;
public BozaSubProcessServiceBusQueueTrigger(BozaSubProcessFactory bozaProcessFactory)
{
this.BozaProcessFactory = bozaProcessFactory;
}
[FunctionName("BozaSubProcessServiceBusQueueTrigger")]
public async Task Run([ServiceBusTrigger("bozasubprocess", Connection = "sb")] Message message,
MessageReceiver messageReceiver,
[ServiceBus("bozasubprocess", Connection = "sb")] MessageSender sender,
ILogger log)
{
try
{
string body = Encoding.UTF8.GetString(message.Body);
//log.LogInformation($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
if (this.accountTransferProcessFactory.GetBozaProcessService(body) != null)
{
log.LogInformation($"Boza Sub Process Invoked");
await this.accountTransferProcessFactory.GetBozaProcessService(body).ExecuteAsync(body);
await messageReceiver.CompleteAsync(message.SystemProperties.LockToken);
}
else
{
log.LogInformation("No any Boza Sub Process Invoked");
}
}
catch (Exception ex)
{
if (!message.UserProperties.ContainsKey(RetryCountUserProperty))
{
message.UserProperties[RetryCountUserProperty] = 0;
message.UserProperties[OriginalSequenceNumber] = message.SystemProperties.SequenceNumber;
}
if ((int)message.UserProperties[RetryCountUserProperty] < RetryCount)
{
Message retryMessage = message.Clone();
int retryCount = (int)message.UserProperties[RetryCountUserProperty] + 1;
int interval = 5 * retryCount;
DateTimeOffset scheduleTime = DateTimeOffset.Now.AddSeconds(interval);
retryMessage.UserProperties[RetryCountUserProperty] = retryCount;
retryMessage.UserProperties[SubProcessException] = ex.Message;
await sender.ScheduleMessageAsync(retryMessage, scheduleTime);
await messageReceiver.CompleteAsync(message.SystemProperties.LockToken);
log.LogInformation($"Scheduling message retry {retryCount} to wait {interval} seconds and arrive at {scheduleTime.UtcDateTime}");
}
else
{
log.LogWarning(message.SystemProperties.LockToken);
log.LogCritical($"Exhausted all retries for message sequence {message.UserProperties["original-SequenceNumber"]}");
await messageReceiver.DeadLetterAsync(message.SystemProperties.LockToken, "Exhausted all retries");
}
}
}
}
Since this exception is raised as part of the service bus extension, you can't directly handle the error (like a try/catch), but can setup retry policies (on top of the default service bus retry). This official doc covers more of this in detail.
Rather than implementing the retry in the catch statement as you're doing, try using the ones provided by the SDK which I believe renew the lock:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.