I'm using deferred messages and manage to retrieve them and process them the way I want. Now I need a way to delete them (normal messages can be "Completed") so they don't stay forever but I can't find out how.
Here's how I retrieve the message:
var message = await ServiceBusReceiver.ReceiveDeferredMessageAsync(
deferredMessage.SequenceNumber,
cancellationToken
);
And this is what I tried first to delete them
await ServiceBusReceiver.CompleteMessageAsync(message, cancellationToken);
Which failed with an error claiming the lock was not valid so I tried
await ServiceBusReceiver.RenewMessageLockAsync(message, cancellationToken);
await ServiceBusReceiver.CompleteMessageAsync(message, cancellationToken);
But the error persist.
EDIT:
I created a demo:
using Azure.Identity;
using Azure.Messaging.ServiceBus;
const string ToDefer = nameof(ToDefer);
const string UnDefer = nameof(UnDefer);
const string TopicName = "demo-deferred-sj";
const string ServiceBusNamespace = "#######";
const string SubscriptionName = "all";
var oneSecondMoreThanLockDuration = TimeSpan.FromSeconds(6);
var userName = System.Environment.GetEnvironmentVariable("USERNAME");
var serviceBusClient = new ServiceBusClient(
$"{ServiceBusNamespace}.servicebus.windows.net",
new VisualStudioCredential()
);
var sender = serviceBusClient.CreateSender(TopicName);
var processor = serviceBusClient.CreateProcessor(TopicName, SubscriptionName, new ServiceBusProcessorOptions
{
AutoCompleteMessages = false
});
var receiver = serviceBusClient.CreateReceiver(TopicName, SubscriptionName);
async Task SendMessagesAsync(string kind, string param = "", DateTimeOffset? scheduleTime = null)
{
var messageId = $"{kind}|{userName}|{param}|{Guid.NewGuid()}";
Console.WriteLine($"Sending {messageId}"
+ (scheduleTime.HasValue ? $" scheduled for {scheduleTime}" : "")
);
var serviceBusMessage = new ServiceBusMessage()
{
MessageId = messageId
};
if (scheduleTime.HasValue)
{
serviceBusMessage.ScheduledEnqueueTime = scheduleTime.Value;
}
await sender.SendMessageAsync(serviceBusMessage);
}
async Task ProcessMessageAsync(ProcessMessageEventArgs args)
{
Console.WriteLine($"Handling {args.Message.MessageId} ");
var messageParts = args.Message.MessageId.Split('|');
var kind = messageParts[0];
var user = messageParts[1];
var param = messageParts[2];
if (user != userName)
{
Console.WriteLine($"Caution handling message of another user: {user}");
}
switch (kind)
{
case ToDefer:
await args.DeferMessageAsync(args.Message);
var scheduleTime = args.Message.EnqueuedTime + oneSecondMoreThanLockDuration;
await SendMessagesAsync(UnDefer, args.Message.SequenceNumber.ToString(), scheduleTime);
break;
case UnDefer:
var deferredMessage = await receiver.ReceiveDeferredMessageAsync(long.Parse(param));
Console.WriteLine($"Deferd message {deferredMessage.MessageId} processed");
await args.CompleteMessageAsync(args.Message);
try
{
// THIS WOULD DELETE THE MESSAGE IF THE LOCK WAS STILL ON
await receiver.CompleteMessageAsync(deferredMessage);
}
catch (Exception ex)
{
Console.WriteLine($"Ignoring {ex.Message}");
}
break;
}
}
processor.ProcessMessageAsync += ProcessMessageAsync;
processor.ProcessErrorAsync += eventArgs =>
{
Console.WriteLine(eventArgs.Exception.Message);
return Task.CompletedTask;
};
var cancellationTokenSource = new CancellationTokenSource();
await processor.StartProcessingAsync(cancellationTokenSource.Token);
await SendMessagesAsync(ToDefer);
Console.ReadKey();
cancellationTokenSource.Cancel();