使用Node.js从Azure WebJob轮询Azure Service Bus队列

时间:2015-05-06 23:50:03

标签: azure azure-web-sites azureservicebus azure-webjobs

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

遇到以下问题:

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

  2. 正在以随机顺序接收消息。不是FIFO。

  3. 有时会收到两次消息,即使它们是在ReceiveAndDelete模式下读取的(我尝试过没有读取模式参数,默认为ReceiveAndDelete,receiveQueueMessage{isReceiveAndDelete:true}相同的结果)。

  4. 当队列为空时,它应该使接收请求保持打开一天,但它总是在230秒后返回no消息错误。根据文件记录,最长为24天,所以我不知道230秒的来源:

  5.   

    Service Bus中阻塞接收操作的最大超时时间   队列是24天。但是,基于REST的超时具有最大值   55秒。

    基本上没有任何广告可行。我做错了什么?

    发送消息测试工作:

    {isPeekLock:false}

    接收消息连续作业:

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

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:1)

关闭Service Bus队列的分区标志也适用于我。

对于分区队列,某些消息的延迟超过30分钟。 一个简单的DotNet webclient可以毫不拖延地下载所有消息。但是,只要nodejs下载消息,只会下载第一条消息而不会出现问题,之后会出现延迟。使用nodejs来更改http代理选项keepalive和套接字超时并没有改善这种情况。

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

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

答案 2 :(得分:1)

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

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