Azure 服务总线队列:我可以 manage/cancel 计划消息吗?

Azure Service Bus Queue: Can I manage/cancel scheduled messages?

如果我以后使用类似这样的方式安排消息:

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

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

那有什么方法可以view/delete 已经安排好的消息吗? send_queue_message 没有 return 任何东西,并且 receive_queue_message 可以理解地没有 return 计划稍后排队的项目 - 所以我无法抓住它通过例如 delete_queue_message

Azure 团队似乎知道该用例,因为存储队列似乎具有类似此功能的功能:https://azure.microsoft.com/en-gb/blog/azure-storage-queues-new-feature-pop-receipt-on-add-message/

基本上我需要能够安排一条消息稍后排队,但可以取消。理想情况下,我还希望能够查看所有未来的计划任务,但能够仅存储一个可用于稍后删除排队消息的 ID 就足够了。

Azure UI 也显示了 active/scheduled 条消息的数量,这似乎表明应该有一些方法可以查看那些预定的消息!

队列存储会更好吗?还是服务总线有一些可行的方法? ScheduledEnqueueTimeUtc 似乎比队列存储中的可见性超时更灵活,所以如果可以的话,最好坚持使用它。

是的,有可能。

不知道 NodeJS 客户端是否支持它,但对于 C# 客户端,有一种方法可以替代我描述的 here ScheduledEnqueueTimeUtc 方法。使用 QueueClient.ScheduleMessageAsync() 您可以发送预定消息并获得 SequenceNumber。然后可以使用 QueueClient.CancelScheduledMessageAsync(sequenceNumber) 在任何时间点使用它来取消消息。

为了完整起见,这可以使用存储队列服务 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

然后在可见性超时到期之前的另一个 Python 实例中:

queue_service.delete_message('queue_name', id, pop_receipt)

您可以使用 "Microsoft.ServiceBus.Messaging" 并按入队时间清除消息。接收消息,按 ScheduledEnqueueTime 过滤,并在消息在特定时间入队时执行清除。

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(); 
 }