6

If I schedule a message in the future using something like this:

d = datetime.utcnow() + timedelta(minutes=5)
task = {"some": "object"}

sbs.send_queue_message(
    qn,
    Message(
        task, 
        broker_properties={'ScheduledEnqueueTimeUtc': d}
    )
)

Then is there a way that I can view/delete messages that have been scheduled? send_queue_message doesn't return anything, and receive_queue_message understandably doesn't return items that are scheduled to be queued later - so I can't get hold of it to pass to delete_queue_message for example.

The Azure team seem aware of the usecase because Storage Queues seem to have something like this feature: https://azure.microsoft.com/en-gb/blog/azure-storage-queues-new-feature-pop-receipt-on-add-message/

Basically I need to be able to schedule a message to be queued later, but have this cancelable. Ideally I'd like to be able to also view all future scheduled tasks, but being able to just store an id that can be used to later delete the queued message would be sufficient.

The Azure UI shows the count of active/scheduled messages too, which seems to suggest there should be some way to see those scheduled ones!

Would queue storage be better for this? Or does service bus have some approach that might work? ScheduledEnqueueTimeUtc seems more flexible than the visibility timeout in queue storage so it'd be nice to stick with it if I can.

Callum M
  • 1,635
  • 19
  • 27

3 Answers3

10

Yes, it's possible.

Don't know if NodeJS client has support for it or not, but with C# client there's an alternative to ScheduledEnqueueTimeUtc approach I've described here. Using QueueClient.ScheduleMessageAsync() you can send a scheduled message and get the SequenceNumber. Which then can be used to cancel the message at any point in time using QueueClient.CancelScheduledMessageAsync(sequenceNumber).

Sean Feldman
  • 23,443
  • 7
  • 55
  • 80
  • Accepting this answer, thanks! I also raised a github issue: https://github.com/Azure/azure-sdk-for-python/issues/3351 on the Python SDK (which is what I'm using currently), the C# one uses a different API and they're rewriting the Python one to do the same longer term. For now though it's only in the C# one I think. – Callum M Sep 17 '18 at 09:27
  • 1
    Since the broker is capable of this feature (it does support C# client), becomes an issue of time until it's ready. Meanwhile, either ASQ (suggested below) or ASB using .NET Standard client would be an option. Depending how much of messaging features you need, ASQ might not be the right fit, but this is your call – Sean Feldman Sep 17 '18 at 19:03
1

You can use "Microsoft.ServiceBus.Messaging" and purge messages by en-queue time. Receive the messages, filter by ScheduledEnqueueTime and perform purge when the message has been en-queued at the specific time.

Microsoft.ServiceBus.Messaging;

MessagingFactory messagingFactory =  MessagingFactory.CreateFromConnectionString(connectionString);

var queueClient = messagingFactory.CreateQueueClient(resourceName, ReceiveMode.PeekLock);

var client = messagingFactory.CreateMessageReceiver(resourceName, ReceiveMode.PeekLock);

BrokeredMessage message = client.Receive();

if (message.EnqueuedTimeUtc < MessageEnqueuedDateTime)
 {
         message.Complete(); 
 }
StuartLC
  • 104,537
  • 17
  • 209
  • 285
Reshma Sulthan
  • 531
  • 5
  • 5
  • Thanks for sharing this! This would be useful in the case where you already have tasks queued already and you don't have sequence numbers for them. I think the accepted answer is better for the case of scheduling new tasks though if you're already using an AMQP version - ultimately I ended up moving to the Java SDK which does have the AMQP integration. – Callum M Oct 04 '18 at 17:30
0

For completeness, this can be done using the storage queue service Python SDK:

from azure.storage.queue import QueueService
account_name = '<snip>'
account_key = '<snip>'
queue_service = QueueService(account_name=account_name, account_key=account_key)
a = queue_service.put_message('queue_name', u'Hello World (delete)', visibility_timeout=30)
print(a.id) # id
print(a.pop_receipt) # pop_receipt

Then in another Python instance before the visibility timeout expires:

queue_service.delete_message('queue_name', id, pop_receipt)
Callum M
  • 1,635
  • 19
  • 27