【问题标题】:Polling an Azure Service Bus Queue from an Azure WebJob using Node.js使用 Node.js 从 Azure WebJob 轮询 Azure 服务总线队列
【发布时间】:2015-05-06 23:50:02
【问题描述】:

尝试使用用 Node.js 编写的 WebJob 轮询 Azure 服务总线队列。我创建了 2 个 WebJobs。第一个是按需向队列发送 10 条唯一消息。第二个作业是连续的并轮询队列中的消息。

遇到以下问题:

  1. 轮询很慢。接收 10 条消息平均需要大约 10 分钟。请参阅下面的示例日志详细信息。在这个速度下基本无法使用。所有的延迟都来自receiveQueueMessage 的回复。响应时间从 0 秒到 ~120 秒不等,平均为 60 秒。

  2. 消息是按随机顺序接收的。不是先进先出。

  3. 1234563 .
  4. 当队列为空时,它应该保持接收请求打开一天,但它总是在 230 秒后返回无消息错误。根据文档,最长为 24 天,所以我不知道 230 秒是从哪里来的:

服务总线中阻塞接收操作的最大超时 排队时间为 24 天。但是,基于 REST 的超时具有最大值 55 秒。

基本上没有什么像宣传的那样有效。我做错了什么?

发送消息测试作业:

var uuid = require('node-uuid');
var azure = require('azure');
var serviceBus = azure.createServiceBusService(process.env.busSearchConnectionString);
var messagesToSend = 10;

sendMessage(0);

function sendMessage(count)
{
    var message = {
        body: 'test message',
        customProperties: {
            message_number: count,
            sent_date: new Date
        },
        brokerProperties: {
            MessageId: uuid.v4() //ensure that service bus doesn't think this is a duplicate message
        }
    };

    serviceBus.sendQueueMessage(process.env.busSearchQueueName, message, function(err) {

        if (!err) {
            console.log('sent test message number ' + count.toString());
        } else {
            console.error('error sending message: ' + err);
        }

    });

    //wait 5 seconds to ensure messages are received by service bus in correct order
    if (count < messagesToSend) {
        setTimeout(function(newCount) {
            //send next message
            sendMessage(newCount);
        }, 5000, count+1);
    }
}    

接收消息连续作业:

console.log('listener job started');
var azure = require('azure');
var serviceBus = azure.createServiceBusService(process.env.busSearchConnectionString);
listenForMessages(serviceBus);

function listenForMessages(serviceBus)
{
    var start = process.hrtime();
    var timeOut = 60*60*24; //long poll for 1 day
    serviceBus.receiveQueueMessage(process.env.busSearchQueueName, {timeoutIntervalInS: timeOut, isReceiveAndDelete: true}, function(err, message) {

        var end = process.hrtime(start);
        console.log('received a response in %ds seconds', end[0]);

        if (err) {

            console.log('error requesting message: ' + err);
            listenForMessages(serviceBus);

        } else {

            if (message !== null && typeof message === 'object' && 'customProperties' in message && 'message_number' in message.customProperties) {

                console.log('received test message number ' + message.customProperties.message_number.toString());
                listenForMessages(serviceBus);

            } else {

                console.log('invalid message received');
                listenForMessages(serviceBus);

            }

        }

    });
}

样本日志输出:

[05/06/2015 21:50:14 > 8c2504: SYS INFO] Status changed to Running
[05/06/2015 21:50:14 > 8c2504: INFO] listener job started
[05/06/2015 21:51:23 > 8c2504: INFO] received a response in 1s seconds
[05/06/2015 21:51:23 > 8c2504: INFO] received test message number 0
[05/06/2015 21:51:25 > 8c2504: INFO] received a response in 2s seconds
[05/06/2015 21:51:26 > 8c2504: INFO] received test message number 4
[05/06/2015 21:51:27 > 8c2504: INFO] received a response in 1s seconds
[05/06/2015 21:51:27 > 8c2504: INFO] received test message number 7
[05/06/2015 21:51:28 > 8c2504: INFO] received a response in 0s seconds
[05/06/2015 21:51:29 > 8c2504: INFO] received test message number 9
[05/06/2015 21:51:49 > 8c2504: INFO] received a response in 20s seconds
[05/06/2015 21:51:49 > 8c2504: INFO] received test message number 1
[05/06/2015 21:53:35 > 8c2504: INFO] received a response in 106s seconds
[05/06/2015 21:53:35 > 8c2504: INFO] received test message number 1
[05/06/2015 21:54:26 > 8c2504: INFO] received a response in 50s seconds
[05/06/2015 21:54:26 > 8c2504: INFO] received test message number 5
[05/06/2015 21:54:35 > 8c2504: INFO] received a response in 9s seconds
[05/06/2015 21:54:35 > 8c2504: INFO] received test message number 9
[05/06/2015 21:55:28 > 8c2504: INFO] received a response in 53s seconds
[05/06/2015 21:55:28 > 8c2504: INFO] received test message number 2
[05/06/2015 21:57:26 > 8c2504: INFO] received a response in 118s seconds
[05/06/2015 21:57:26 > 8c2504: INFO] received test message number 6
[05/06/2015 21:58:28 > 8c2504: INFO] received a response in 61s seconds
[05/06/2015 21:58:28 > 8c2504: INFO] received test message number 8
[05/06/2015 22:00:35 > 8c2504: INFO] received a response in 126s seconds
[05/06/2015 22:00:35 > 8c2504: INFO] received test message number 3
[05/06/2015 22:04:25 > 8c2504: INFO] received a response in 230s seconds
[05/06/2015 22:04:25 > 8c2504: INFO] error requesting message: No messages to receive
[05/06/2015 22:08:16 > 8c2504: INFO] received a response in 230s seconds    
[05/06/2015 22:04:25 > 8c2504: INFO] error requesting message: No messages to receive

【问题讨论】:

    标签: azure azure-web-app-service azureservicebus azure-webjobs


    【解决方案1】:

    问题是我使用的队列已分区(在 Azure 门户中创建队列时的默认选项)。一旦我创建了一个未分区的新队列,一切都按预期工作而没有延迟(除了长轮询尝试中奇怪的 230 秒超时)。所以基本上 node.js 库不适用于分区队列。完全没有。浪费了很多天来弄清楚这一点。将这里留给其他人。

    【讨论】:

    • 嘿乔尔。我知道这与问题无关,但因为这是一个新问题。您是如何设置新的 WebJob 的?我在 Azure 的旧门户或新门户上的任何菜单上都找不到任何选项......我很难过和绝望......谷歌在这方面没有帮助:(
    • 您需要先设置一个“网络应用程序”,它是网络应用程序下的一个选项。然后,您可以使用 git 持续集成将其部署到它。见here
    • 非常感谢!我已经有一个通过 Github 作为网络应用程序部署的网络 API。我将在此处添加 WebJobs。
    • 您最终在 Node 端获得了什么样的接收速度?每秒多少条消息?我看到最多 5 或 6 条消息/秒
    • @Joel 你可以使用 amqp
    【解决方案2】:

    关闭服务总线队列的分区标志也对我有用。

    对于分区队列,一些消息的延迟超过 30 分钟。 一个简单的 DotNet webclient 可以毫无延迟地下载所有消息。但是,一旦 nodejs 应该下载消息,只会下载第一条消息而没有问题,然后出现延迟。使用 nodejs 更改 http 代理选项 keepalive 和 socket timeout 并没有改善这种情况。

    停止 nodejs 后,我不得不等待几分钟,DotNet 客户端才真正开始正常工作。这可以重复多次。我还发现简单的DotNet webclient程序在连续启动和停止几次后也出现了类似的问题。

    无论如何,您的帖子向我展示了解决方案:关闭分区标志:)

    【讨论】:

      【解决方案3】:

      尝试使用 amqp 从 azure 服务总线分区队列 中读取消息,这将适用于分区主题/队列,您甚至不必进行很多轮询。

      const AMQPClient = require('amqp10').Client;
      const Policy = require('amqp10').Policy;
      
      const protocol = 'amqps';
      const keyName = 'RootManageSharedAccessKey';
      const sasKey = 'your_key_goes_here';
      const serviceBusHost = 'namespace.servicebus.windows.net';
      const uri = `${protocol}://${encodeURIComponent(keyName)}:${encodeURIComponent(sasKey)}@${serviceBusHost}`;
      const queueName = 'partitionedQueueName';
      const client = new AMQPClient(Policy.ServiceBusQueue);
      client.connect(uri)
      .then(() => Promise.all([client.createReceiver(queueName)]))
      .spread((receiver) => {
          console.log('--------------------------------------------------------------------------');
          receiver.on('errorReceived', (err) => {
              // check for errors
              console.log(err);
          });
          receiver.on('message', (message) => {
              console.log('Received message');
              console.log(message);
              console.log('----------------------------------------------------------------------------');
          });
      })
      .error((e) => {
          console.warn('connection error: ', e);
      });
      

      https://www.npmjs.com/package/amqp10

      【讨论】:

        猜你喜欢
        • 2017-02-25
        • 2015-07-18
        • 2015-06-02
        • 2014-12-21
        • 2020-12-17
        • 2018-04-01
        • 2013-08-19
        • 2015-06-08
        • 1970-01-01
        相关资源
        最近更新 更多