適材適所なのでNode.jsで、同じ事をする必要はありませんが実験として。
よくあるキューのパターン
以下は、ありがちなキューをポーリングするサンプル。メッセージがあれば連続して取り出すし、無ければ10秒間スリープする。
while (true) { Console.WriteLine("polling..."); var msg = q.GetMessage(TimeSpan.FromSeconds(30)); if (msg != null) { Console.WriteLine("get message"); Console.WriteLine(msg.AsString); Console.WriteLine("delete message"); q.DeleteMessage(msg); } else { Console.WriteLine("message is null"); System.Threading.Thread.Sleep(10000); } }
Node.js で実装する
whileで書くってのは違うだろうというか、色々ブロックしてしまうのでNodeの作法ではないと思われ。ここではsetIntervalを使って10秒毎にタイマを起動してみる。また、.NETと違い、getMessageメソッドは存在しないが、getMessagesの既定動作だと、1つしかメッセージを取得しない。取得されたメッセージは配列に格納されている。
以下、実装したサンプル。ネストが深くなってしまうのはしょうがないのですが、連続して取得する部分は再帰でごまかしす。
var azure = require('azure'); var queueService = azure.createQueueService(); var queueName = 'samplequeue'; var getMessages = function() { // この引数だと、1個しかメッセージを取得しない。Timeout は30秒。 queueService.getMessages(queueName, function(error, msgs) { console.log('polling...'); if(!error && msgs.length > 0) { console.log('get messages (%d)', msgs.length); console.log(msgs[0]); for(var i = 0;i < msgs.length; i++) { queueService.deleteMessage(queueName, msgs[0].messageid, mgs[0].popreceipt, function(error){ if(!error){ // Message deleted console.log('delete message'); } }); } // メッセージがあったら取得 getMessages(); } }); } // キューの作成 queueService.createQueueIfNotExists(queueName, function(error) { if(!error) { console.log('queue was created.'); // 10秒間隔でポーリング setInterval(getMessages, 10000); } });
以下結果。
polling... get messages (1) { messageid: 'af74d330-5f65-43e1-804a-e465be3cd3d9', insertiontime: 'Wed, 09 May 2012 14:25:03 GMT', expirationtime: 'Wed, 16 May 2012 14:25:03 GMT', dequeuecount: '1', popreceipt: 'gC8x7wb8zggBAAAA', timenextvisible: 'Wed, 09 May 2012 14:27:01 GMT', messagetext: 'Hello World 6' } delete message polling... get messages (1) { messageid: 'fabbf505-10ba-48cb-9c6a-cc5c46b7d3d7', insertiontime: 'Wed, 09 May 2012 14:25:03 GMT', expirationtime: 'Wed, 16 May 2012 14:25:03 GMT', dequeuecount: '1', popreceipt: 'UAwp9Qb8zggBAAAA', timenextvisible: 'Wed, 09 May 2012 14:27:11 GMT', messagetext: 'Hello World 7' } delete message
このような処理で他の処理をブロックしないのか、再帰しすぎてスタックオーバーフローとかしないのかが良く分からない。Storageエミュレータ上で1000個程度メッセージを入れたところで問題はなかったが。
ふとコードを読み返してみて、再帰部分をsetTimeoutしたほうが、非同期で他の処理をブロックしないのかなと思ったり。
// メッセージがあったら取得 setTimeout(getMessages,0);
もっとスマートな書き方があるような気もしますが...