3

我正在开发一个从 Azure 服务总线队列中提取消息的 Java 应用程序。我正在使用 Java Azure API (com.microsoft.windowsazure.services)。我遇到的问题是代理消息在处理后删除有时会失败。

我的应用程序使用 ServiceBusContract 对象上的 receiveQueueMessage() 方法,使用 peek-lock 接收模式从队列中提取消息。成功处理消息后,我通过调用 deleteMessage() 方法从队列中删除消息(我相信此方法对应于 .NET API 中的 Complete() 方法)。

但是,有时此方法调用会失败。deleteMessage() 将 com.sun.jersey.api.client.UniformInterfaceException 异常记录到控制台,它不会抛出此异常(我将在下面生成输出)。该异常似乎表明找不到该消息。发生这种情况时,消息将保留在队列中。实际上,下一次调用 receiveQueueMessage() 会再次检索此消息。然后删除失败一次或两次,然后成功。此后检索到的消息成功删除。

下面是出现问题的代码:

ReceiveMessageOptions receiveOptions = ReceiveMessageOptions.DEFAULT; 
receiveOptions.setReceiveMode(ReceiveMode.PEEK_LOCK); 
BrokeredMessage message = serviceBus.receiveQueueMessage("my_queue",receiveOptions).getValue(); 
// Process the message 
System.out.println("Delete message with ID: "+message.getMessageId());
serviceBus.deleteMessage(message);

以下是出现问题时的输出示例:

Delete message with ID: 100790000086491
2013/01/22 12:58:29 com.microsoft.windowsazure.services.serviceBus.implementation.ServiceBusExceptionProcessor processCatch
WARNING: com.sun.jersey.api.client.UniformInterfaceException: DELETE https://voyagernetzmessaging.servicebus.windows.net/sms_queue/messages/24/efa56a1c-95e8-4cd6-931a-972eac21563a returned a response status of 404 Not Found
com.sun.jersey.api.client.UniformInterfaceException: DELETE https://voyagernetzmessaging.servicebus.windows.net/sms_queue/messages/24/efa56a1c-95e8-4cd6-931a-972eac21563a returned a response status of 404 Not Found
    at com.sun.jersey.api.client.WebResource.voidHandle(WebResource.java:697)
    at com.sun.jersey.api.client.WebResource.delete(WebResource.java:261)
    at com.microsoft.windowsazure.services.serviceBus.implementation.ServiceBusRestProxy.deleteMessage(ServiceBusRestProxy.java:260)
    at com.microsoft.windowsazure.services.serviceBus.implementation.ServiceBusExceptionProcessor.deleteMessage(ServiceBusExceptionProcessor.java:176)
    at microworks.voyagernetzmessaging.smsservice.SmsSender$Runner.finalizeSms(SmsSender.java:114)
    at microworks.voyagernetzmessaging.smsservice.SmsSender$Runner.finalizeSms(SmsSender.java:119)
    at microworks.voyagernetzmessaging.smsservice.SmsSender$Runner.run(SmsSender.java:340)
com.microsoft.windowsazure.services.core.ServiceException: com.sun.jersey.api.client.UniformInterfaceException: DELETE https://voyagernetzmessaging.servicebus.windows.net/sms_queue/messages/24/efa56a1c-95e8-4cd6-931a-972eac21563a returned a response status of 404 Not Found
Response Body: <Error><Code>404</Code><Detail>The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue..TrackingId:4b112c5a-5919-4680-b6bb-e10a2c081ba3_G15_B9,TimeStamp:1/22/2013 10:58:30 AM</Detail></Error>
    at com.microsoft.windowsazure.services.serviceBus.implementation.ServiceBusExceptionProcessor.deleteMessage(ServiceBusExceptionProcessor.java:179)
    at microworks.voyagernetzmessaging.smsservice.SmsSender$Runner.finalizeSms(SmsSender.java:114)
    at microworks.voyagernetzmessaging.smsservice.SmsSender$Runner.finalizeSms(SmsSender.java:119)
    at microworks.voyagernetzmessaging.smsservice.SmsSender$Runner.run(SmsSender.java:340)
Caused by: com.sun.jersey.api.client.UniformInterfaceException: DELETE https://voyagernetzmessaging.servicebus.windows.net/sms_queue/messages/24/efa56a1c-95e8-4cd6-931a-972eac21563a returned a response status of 404 Not Found
    at com.sun.jersey.api.client.WebResource.voidHandle(WebResource.java:697)
    at com.sun.jersey.api.client.WebResource.delete(WebResource.java:261)
    at com.microsoft.windowsazure.services.serviceBus.implementation.ServiceBusRestProxy.deleteMessage(ServiceBusRestProxy.java:260)
    at com.microsoft.windowsazure.services.serviceBus.implementation.ServiceBusExceptionProcessor.deleteMessage(ServiceBusExceptionProcessor.java:176)
    ... 3 more

请注意,异常中的 URI 似乎引用了不同的消息 ID(efa56a1c-95e8-4cd6-931a-972eac21563a,而消息的 ID 实际上是 100790000086491)。我不知道这是否是失败的关键,但我有一种预感。

另一个有趣的观察:看起来错误总是发生在应用程序启动后从队列中检索到的第一条消息中,或者在队列为空之后。此后收到的所有消息似乎都不会导致此类问题。

该队列的锁定持续时间为 2 分钟,并且消息的处理在该持续时间内完成,因此过期的锁定不是原因。

有任何想法吗?

4

2 回答 2

5

我建议您调用 BrokeredMessage 类的 Complete()。因此,在您的情况下,请尝试致电:

消息。完成();

当服务总线看到 Complete() 时,它认为该消息已被消费并将其从队列中删除。

于 2013-01-24T09:50:11.253 回答
3

出现在 URL 中的 UUID 是服务器用来跟踪哪个消息被锁定的随机令牌;它不应该与消息 ID 相同。您可以使用 访问锁定 URL message.getLockLocation()

您拥有的代码看起来是正确的,我看不出它会失败的任何明显原因,尤其是在您描述的内容中。需要检查的一些事项:

  1. 检查您收到的消息是否有效。如果你 peek-lock 一个空队列,它将返回一个空消息。那么锁定位置应该是null。(但这不会导致您看到的失败。)
  2. lock supplied is invalid如果您尝试多次删除同一条消息,您可能会收到错误消息。如果您的代码注意到服务何时返回空消息并替换之前的消息,则可能会发生这种情况。(但这并不能解释为什么尝试删除该消息最终会奏效,除非它是被删除的另一条消息。)

希望这会有所帮助!

于 2013-02-07T23:36:50.813 回答