2017-02-23 12 views
1

私はHapiフレームワークでnode.jsサーバーを開発しています。私はRabbitMQ(amqp)を採用して私の仕事を待ちました。ただし、リクエストが送信されるとすぐにリクエストに返信するのではなく、実際の機能がコンシューマとして設定されているRabbitサーバにメッセージが送信されます。次に、消費者は結果を(要求、応答)関数に戻し、関数に応答させる必要があります。Node.jsスクリプト間のデータ転送

私の解決策は、私のワーカーファイル(amqpコンシューマが所在する場所)に変数を作成してエクスポートすることです。次に、インデックスファイル(私のメインスクリプトとルートハンドラ)で、私は変数をインポートします。要求が受信されると、RabbitMQサーバにメッセージが送信され、サーバによって変数が変更されます。次に、インデックスファイルに戻り、スクリプトは変数の値を更新してから返信します。明らかに、非同期のため、プログラムは前の要求の結果に応答します。

私はいくつかの調査を行い、スクリプト間で変数を共有することは想定されていません。誰にも解決策がありますか?私の目的は、私のamqpの消費者をスクリプトに入れられることです。スクリプトを実行すると、コンシューマーは対応するメッセージを受け取る準備が整います。次に、私のインデックスファイルで、要求が受信されると、RabbitMQサーバにメッセージが送信されます。そしてそれは消費者の結果をつかみ、それに答えるべきです。以下は

私のコードです:

index.ts

import * as Joi from "joi"; 
import * as amqp from "amqplib/callback_api"; 
import * as waitUntil from "wait-until"; 

import * as repository from "./repository"; 
import * as worker from "./worker"; 

// defien variables from internal modules 
let greeter = new repository.Greeter(); 

// register type 
import {Register} from "../../interfaces"; 

// define amqp related stuff 
let greeterReply = worker.greeterReply; 

// helloWorld config including handler, validate and auth 
export let register: Register = (server, options, next) => { 
    server.route([ 
    { 
     method: "GET", 
     path: "/greeter", 
     config: { 
      handler: (request, reply) => { 
       let q: string = "greeter"; 
       let requestQuery = request.query; 
       let requestString = JSON.stringify(requestQuery); 
       amqp.connect("amqp://192.168.0.31", (err, conn) => { 
        conn.createChannel((err, ch) => { 
         ch.assertQueue(q, {durable: false}); 
         ch.sendToQueue(q, new Buffer(requestString)); 
        }); 
       }); 
       waitUntil(500, 10, function condition() { 
        greeterReply = worker.greeterReply; 
        return (greeterReply !== null); 
       }, function done(result) { 
        reply(greeterReply); 
        greeterReply = null; 
       }); 
      }, 
      validate: { 
       query: { 
        name: Joi.string(), 
        age: Joi.number() 
       } 
      }, 
     } 
    } 
    ]); 
    next(); 
}; 

register.attributes = { 
    name: "greeter", 
    version: "1.0" 
}; 

worker.ts

// import external modules 
import * as amqp from "amqplib/callback_api"; 

// import internal modules 
import * as repository from "./repository"; 
import * as indexModule from "./index"; 

// defien variables from internal modules 
let greeter = new repository.Greeter(); 

export let greeterReply = null; 

amqp.connect("amqp://192.168.0.31", (err, conn) => { 
    conn.createChannel((err, ch) => { 
     let q: string = "greeter"; 
     ch.assertQueue(q, {durable: false}); 
     ch.consume(q, function (requestString) { 
      let newRequest = JSON.parse(requestString.content.toString()); 
      console.log("replied via amqp"); 
      let result: string = "how are you"; 
      result = greeter.helloWorld(newRequest.name, newRequest.age); 
      console.log("the result is: ", result); 
      greeterReply = result; 
     }, {noAck: true}); 
    }); 
}); 
+0

このタイプのものをカプセル化するためのプラグインを見てください。また、ワーカー関数でコールバックを使用して処理をトリガーし、制御します。クラスを使用することで、各リクエストの状態をカプセル化することができますが、高いスループットを目指す場合、最終的に問題になる可能性があります。 –

+0

コールバック関数を使用すると、インデックスファイルの関数を呼び出す必要がありますか?これは私がやろうとするものではありません。私はかなり多くのルートを扱っています。プラグインの方法について詳しく説明できますか?プラグインとしてamqpを登録するにはどうすればいいですか? – zhangjinzhou

答えて

1

あなたがRabbitMQのオーバーRPCのようなものである必要がどのような。これは、tutorials hereに示されているように、RabbitMQによってサポートされています。

既に使用しているamqplibを使用して実装することも、amqp-rpcなどの特定のモジュールを使用して実装することもできます。

+0

私はそれが解決策だと信じています!あなたよりも。しかし、RPCを使用せずに、端末でワーカーを実行しないと、私のプログラム(上記のコード)がうまく動作することに気付きます。パブリッシャーがメッセージを送信すると、コンシューマーは子プロセスとして実行されるように見えます。理由を知っていますか? @tbking – zhangjinzhou

+0

これは、ワーカーファイルをインポートしたためです。つまり、インデックスファイルを実行するだけで、ワーカーファイルが実行され、ワー​​カー自身が呼び出されます。 あなたのコードは、これらのファイルを別々に実行する必要はありません。 – tbking

+0

ありがとうございました!この場合、まだRPCを使用する必要があると思いますか?もしそうなら、私はどんな利益を得ることができますか? – zhangjinzhou

関連する問題