2016-03-11 11 views
6

Herokuで動作するNode JSサーバをメッセージキューアーキテクチャに移動する必要があります。現在、サーバーはHTTP要求を受け取り、何らかの処理を行い、応答します。問題は、特にリクエストがたくさんあるときは、処理に時間がかかることです。この長い処理時間は、サーバーのタイムアウト、過負荷、クラッシュを引き起こします。私の読書は、処理を行うバックグラウンドワーカーの必要性を私に教えてくれます。ノードHeroku上のJSメッセージキュー

私はメッセージキューとバックグラウンドワーカーに関する経験はありません。私は始めに非常に簡単な例を探しています。誰も簡単でわかりやすいモジュールや例を提案することができますか?

私はいくつかを見つけましたexamplesしかし、彼らは複雑で、私は迷子になっています!私が構築できるベアボーンの例がほしい。

+0

クール私が見ることができるスクリーンキャストのプレビュー/サンプルがありますか?私はこれが正しいレベルであるかどうかを知りたい。あなたが教えていることはヘロクにも当てはまりますか? – user3320795

+1

インタビューの1つは無料で、ここでは:https://sub.watchmecode.net/episode/rmq-interviews-udi-dahan/しかし、私はプレビューのために多くを持っていない、そうでなければ...私はプレビューをまとめなければならないビデオ –

答えて

8

はのは、RabbitMQのでこれを行う方法を見てみましょう。 まず、開発環境で動作させるにはRabbitMQサーバが必要です。 あなたはすでにそれを持っていない場合は、次のようにあなたが(Ubuntuのまたは同様に)インストールすることができます(「sudoのサービスのRabbitMQサーバの状態を」確認してください):

:サーバがで走ら、

sudo su -c "echo 'deb http://www.rabbitmq.com/debian/ testing main' >> /etc/apt/sources.list" 
wget http://www.rabbitmq.com/rabbitmq-signing-key-public.asc 
sudo apt-key add rabbitmq-signing-key-public.asc 
sudo apt-get update 
sudo apt-get install rabbitmq-server 
rm rabbitmq-signing-key-public.asc 

を次に

sudo service rabbitmq-server start 

また、Herokuの展開用にRabbitMQサービスを設定する必要があります。この例ではCloudAMPQを使ってみましょう。あなたのHerokuのアプリで新しいCLOUDAMQP_URL環境変数を作成します

heroku addons:create cloudamqp:lemur 

:あなたは、あなたとHerokuのアプリへの無料プランを追加することができます。

次に、node.jsアプリケーションに適したRabbitMQクライアントが必要になります。 がありそこにそれらのいくつかありますが、この例では、のはampqlib使ってみましょう:

あなたのpackage.jsonの依存関係に次の行のようなものを追加する必要があり
npm install ampqlib --save 

"amqplib": "^0.4.1", 

次のことをHerokuアプリにバックグラウンドの「ワーカー」dynoを追加することです。 現在のところ、Procfileには1つのWeb dynoしかありません。 だから、あなたのような、労働者をインスタンス化するための別の行を追加する必要があります

worker: node myworker.js 

最後に、あなたはRabbitMQのを経由して、あなたのワーカーダイノと対話するようにWebダイノを可能にするコードを記述する必要があります。

この例では、Web dynoがRabbitMQメッセージキューにメッセージを「公開」し、ワーカーdynoがこれらのメッセージを「消費する」と仮定します。

まず、メッセージキューに公開するためのコードを記述しましょう。このコードは、Webダイノのどこかで実行する必要があります。

// Define ampq_url to point to CLOUDAMPQ_URL on Heroku, or local RabbitMQ server in dev environment 
var ampq_url = process.env.CLOUDAMQP_URL || "amqp://localhost"; 
var ampq_open = require('amqplib'); 
var publisherChnl; 

function createPublisherChannel() { 

    // Create an AMPQ "connection" 
    ampq_open.connect(ampq_url) 
     .then(function(conn) { 
      // You need to create at least one AMPQ "channel" on your connection 
      var ok = conn.createChannel(); 
      ok = ok.then(function(ch){ 
       publisherChnl = ch; 
       // Now create a queue for the actual messages to be sent to the worker dyno 
       publisherChnl.assertQueue('my-worker-q'); 
      }) 
     }) 
    } 

function publishMsg() { 
    // Send the worker a message 
    publisherChnl.sendToQueue('my-worker-q', new Buffer('Hello world from Web dyno')); 
} 

あなたのWebダイノの初期化中createPublisherChannel()を呼び出す必要があります。次に、キューにメッセージを送信するたびにpublishMsg()を呼び出します。

最後に、上記のメッセージを消費するためのコードをworker dynoに書きましょう。したがって、たとえば、myworker.jsに次のようなものを追加します。

// Just like in Web dyno... 
var amqp_url = process.env.CLOUDAMQP_URL || "amqp://localhost"; 
var open_ampq = require('amqplib').connect(amqp_url); 
var consumerChnl;  

// Creates an AMPQ channel for consuming messages on 'my-worker-q' 
function createConsumerChannel() {  
    open_ampq 
     .then(function(conn) { 
      conn.createChannel() 
       .then(function(ch) { 
        ch.assertQueue('my-worker-q'); 
        consumerChnl = ch; 
      }); 
     }); 
} 

function startConsuming() { 
    consumerChnl.consume('my-worker-q', function(msg){ 
     if (msg !== null) { 
      console.log(msg.content.toString()); 
      // Tell RabbitMQ server we have consumed the message 
      consumerChnl.ack(msg); 
     } 
    }) 
} 

createConsumerChnl().then(startConsuming); 

最後に、「Herokuのはローカル」でテスト。あなたは今あなたのアプリケーションで実行されている2つのプロセス "Web"と "ワーカー"を持っていることがわかります。あなたのWeb dynoでpublishMsg()を呼び出すたびに、wroker dynoがメッセージの内容をコンソールに吐き出されることを期待してください。あなたのRabbitMQキューで何が起こっているのかを見るには、次のようにしてください:

sudo rabbitmqctl list_queues 
+1

この説明をお寄せいただき、ありがとうございます。私は1つの質問を持っています..異なるモジュール間でこのpublisherChnlをどのように共有しますか? – shagrin

+0

Webアプリケーションの複数のnode.jsモジュールからキューにメッセージを公開したいと思っていますか? その場合は、単純に "exports.publishMsg = publishMsg"という関数publishMsgをエクスポートして、どこからでも呼び出すことができます。 それがあなたの意図したものでない場合は、明確にしてください。 –

+0

はい、それは私の質問でした。明確化のためにありがとう。もう1つの疑問があります。このコードを試したところ、startConsuming()はcreateConsumerChannel()が実行される前に実行されていたようです。それをチェーンする最良の方法は何ですか?私はstartConsuming()を 'consumerChnl = ch;'の直後に呼び出して動作させることができますが、それは正しい方法ですか? – shagrin