2016-03-11 16 views
6

Potrzebuję przenieść mój serwer węzłów JS działający na Heroku do architektury kolejki komunikatów. Obecnie serwer odbiera żądanie HTTP, przetwarza je i odpowiada. Problem polega na tym, że przetwarzanie zajmuje trochę czasu, zwłaszcza gdy jest wiele żądań. Ten długi czas przetwarzania powoduje przekroczenie limitu czasu, przeciążenie i awarię serwera! Moje czytanie mówi mi o potrzebie przetwarzania w tle przez pracownika działającego w tle.Kolejka komunikatów węzła JS na Heroku

Mam zerowe doświadczenie z kolejkami wiadomości i pracownikami w tle i szukam bardzo prostego przykładu, aby zacząć. Czy każdy może zaproponować prosty, zrozumiały moduł lub przykład, aby rozpocząć?

Znalazłem niektóre examples, ale są one złożone i się gubię! Chcę mieć prosty przykład, z którego mogę zbudować.

+0

Cool. Czy widzę jakiś podgląd/próbkę screencastu? Chcę sprawdzić, czy to właściwy poziom. Czy to, czego uczysz, dotyczy Heroku? – user3320795

+1

jedno z wywiadów jest darmowe, tutaj: https://sub.watchmecode.net/episode/rmq-interviews-udi-dahan/ ale nie mam wiele na podglądy, w przeciwnym razie ... powinienem przygotować podgląd video –

Odpowiedz

8

Zobaczmy, jak to zrobić z RabbitMQ. Po pierwsze, będziesz potrzebować serwera RabbitMQ do pracy z twoim środowiskiem programistycznym. Jeżeli nie masz jeszcze go (sprawdź „usługa statusu RabbitMQ-server sudo”) można zainstalować (na ubuntu lub podobny) w następujący sposób:

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 

Następnie dostać serwer działa z:

sudo service rabbitmq-server start 

Należy również skonfigurować usługę RabbitMQ dla wdrożenia Heroku. Użyjmy CloudAMPQ dla tego przykładu. Możesz dodać swym wolnym Plan do swojej aplikacji Heroku z:

heroku addons:create cloudamqp:lemur 

który stworzy nową zmienną środowiskową CLOUDAMQP_URL w aplikacji Heroku.

Następnie będziesz potrzebować odpowiedniego klienta RabbitMQ dla swojej aplikacji node.js. Istnieje kilka z nich tam, ale na tym przykładzie, użyjmy ampqlib:

npm install ampqlib --save 

To powinno dodać coś w rodzaju poniższej linii w swoich zależnościach package.json:

"amqplib": "^0.4.1", 

Następną rzeczą jest dodanie tła "worker" do swojej aplikacji Heroku. Zakładam, że obecnie masz tylko jedno internetowe dyno w swoim Procfile. Więc trzeba dodać kolejną linię do instancji pracownika, takich jak:

worker: node myworker.js 

Wreszcie, trzeba napisać kod, który pozwoli swój dyno internetowej interakcji z hamowni pracownika poprzez RabbitMQ.

Dla tego przykładu założę, że twoje internetowe dyno będzie "publikować" wiadomości do kolejki komunikatów RabbitMQ, a twoje dyno robocze będzie "konsumować" te wiadomości.

Zacznijmy od napisania kodu do opublikowania w kolejce wiadomości. Ten kod musi uruchomić gdzieś w hamowni internetowej:

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

Trzeba będzie zadzwonić createPublisherChannel() podczas inicjalizacji Twojej hamowni internetowej.Następnie wywołaj metodę publishMsg(), gdy chcesz wysłać wiadomość do kolejki.

Wreszcie, napiszmy kod do spożytkowania powyższej wiadomości w dyna pracownika. Tak więc, na przykład, dodać coś jak poniżej w 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); 

Wreszcie, test z "Heroku lokalny". Powinieneś zobaczyć, że masz teraz 2 procesy uruchomione w Twojej aplikacji "Web" i "pracownik". Za każdym razem, gdy wywołasz metodę publishMsg() w swoim dyno, powinieneś zobaczyć, jak dyno wypluwa zawartość wiadomości na konsolę. Aby zobaczyć, co dzieje się w kolejkach RabbitMQ, możesz użyć:

sudo rabbitmqctl list_queues 
+1

Dzięki za wyjaśnienie, bardzo pomocne. Mam jednak jedno pytanie ... jak udostępnić ten moduł publisherers między różnymi modułami? – shagrin

+0

Zakładam, że chcesz mieć możliwość publikowania wiadomości w swoich kolejkach z wielu modułów node.js w swojej aplikacji internetowej? Jeśli tak, po prostu wyeksportuj funkcję publishMsg za pomocą "exports.publishMsg = publishMsg", aby móc wywołać ją z dowolnego miejsca. Jeśli nie o to ci chodziło, to wyjaśnij to. –

+0

Tak, to było moje pytanie. Dzięki za wyjaśnienie. Mam jeszcze jedną wątpliwość myślałem .. Spróbowałem tego kodu i wygląda na to, że startConsuming() jest uruchamiany przed zakończeniem createConsumerChannel(). Jaki jest najlepszy sposób na jego połączenie? Mogę sprawić, żeby zadzwonił do funkcji startConsuming() zaraz po 'consumerChnl = ch;' ale czy jest to właściwa droga? – shagrin

Powiązane problemy