6

Ich habe einen Webserver in Knoten JS auf Heroku geschrieben. Der Server verfügt über einen Webserverprozess und einen Arbeitsprozess. Der Webserver sendet erfolgreich Nachrichten über eine RabbitMQ-Warteschlange an den Worker. Der Worker gibt die verarbeiteten Daten erfolgreich an den Webserver zurück. Ich verwende ein zufällig generiertes Uuid, um die Nachrichten zu verfolgen und sicherzustellen, dass die richtige Nachricht mit der richtigen ursprünglichen Nachricht verknüpft ist.Message Queue Architektur (Client zu Webserver zu Arbeiter und zurück)

In einem separaten Projekt habe ich den Client (Website) erfolgreich mit dem Webserver kommunizieren. Jetzt muss ich die beiden zusammensetzen.

Wie kann ich es so:

  1. Client sendet eine HTTP-POST.
  2. Webserver empfängt die Anforderung und übergibt die Anforderung in der Nachrichtenwarteschlange.
  3. Worker verarbeitet die Anfrage und kehrt zum Webserver zurück.
  4. Der Webserver gibt die korrekten Daten an den Client zurück, damit der Client die Antwort der ursprünglichen Anforderung zuordnen kann.

Schritt 4 ist, wo ich feststecke. Ich glaube irgendwo habe ich gelesen, dass der Client den Webserver ständig abfragen soll (HTTP POSTs?), Bis die Daten fertig sind. Ich denke, ich muss nach Schritt 1 auf den Client antworten, damit die Anfrage nicht ausläuft. Irgendwelche Ideen/Rat geschätzt!

Blockschaltbild: enter image description here

+0

Ist dies ein lang laufender Prozess, in dem Sie Status-Updates benötigen? Oder wird dies eine sehr schnelle Antwort vom Back-End sein, wo die ursprüngliche HTTP-Anfrage eine Antwort mit Daten von diesem Back-End-Dienst erhalten sollte? –

+0

Statusupdates denke ich.Manchmal ist das Back-End 30 Sekunden +. – user3320795

+1

Ja, für etwas länger als eine Sekunde oder so, Status-Updates ist der Weg zu gehen. Ich werde in Kürze eine Antwort posten. –

Antwort

5

Die kurze Version von dem, was Sie tun müssen, um Zwei-Wege-Messaging. Ihre Web-App muss ein Nachrichtenproduzent und ein Nachrichtenkonsument sein. Das Gleiche gilt für Ihren Back-End-Service.

Wenn die HTTP-Anfrage eingeht, sendet der Webserver eine Nachricht über RabbitMQ. Das Back-End nimmt es irgendwann in der Zukunft auf. In der Zwischenzeit sendet der Webserver eine Antwort über die HTTP-Anfrage zurück und sagt, dass etwas passiert und der Benutzer wird später benachrichtigt.

Wenn Sie Express verwenden, wäre es so etwas wie folgt aussehen:


var router = express.Router(); 
router.post("/", postJob); 

function postJob(req, res, next){ 
    req.session.inProgress = true; 

    var msg = { 
    job: "do some work" 
    }; 

    jobSender.sendJobRequest(msg, function(err){ 
    if (err) { return next(err); } 
    res.render("some-response"); 
    }); 
} 

Dieser Code viele Annahmen macht, wie jobSender mit einem Verfahren eine Art von eingekapselten Objekt ist eine Nachricht über RabbitMQ schicken . Ich bin sicher, dass Sie die Details zum Senden einer Nachricht basierend auf dem, was Sie bereits gesagt haben, ausfüllen können.

Wichtig ist, dass der HTTP-Request-Handler die Nachricht über RabbitMQ sendet und anschließend eine HTTP-Antwort an den Webbrowser zurücksendet.

An dieser Stelle kann der Browser tun, was immer er tun muss.

Auf der Back-End, wenn der andere Dienst es Arbeit abgeschlossen hat, muss sie eines von zwei Dingen tun:

1) irgendwo eine gemeinsame Datenbank aktualisieren, so dass Ihr Webserver weiß, welche Arbeit hat geschehen (und kann einen Status lesen)

oder

2) senden eine Nachricht zurück an den Web-Server, über rabbitmq

Option # 1 nicht immer eine gute Option sein, aus verschiedenen Gründen. und von deiner Frage willst du sowieso Option # 2.

Sie benötigen eine zweite Warteschlange - eine, die der Webserver hört. Wenn der Webserver eine Nachricht von dieser Warteschlange empfängt, aktualisiert er seine eigene Datenbank mit dem Status, der empfangen wird.

Dieser Status kann "vollständig" oder "in Bearbeitung" oder "Fehler" oder etwas anderes sein, das Sie für richtig halten.

Wenn Sie zum Beispiel eine Meldung "Auftragsstatus" haben, haben Sie möglicherweise eine Abstraktion namens "JobStatusReceiver", um die Statusmeldung zu erhalten.

Ein einfaches Modul wie dies könnte Nachrichten aus Ihrem Auftragsstatus Warteschlange, empfangen und eine lokale Datenbank aktualisiert mit dem Status


var JobStatusReceiver = require("./jobStatusReceiver"); 
var someDataObject = require("someDataObject"); 

var jobStatus = { 

    listen: function(){ 
    var receiver = new JobStatusReceiver(); 
    receiver.receive(function(statusMessage){ 

     someDataObject.status = statusMessage.status; 
     someDataObject.data = statusMessage.data; 


     someDataObject.save(); 
    }); 
    } 

}; 

module.exports = jobStatus; 

beachten Sie, dass diese im Web-Server können passieren, aber es ist nicht Teil einer HTTP-Anfrage Die Nachricht kam über RabbitMQ mit dem JobStatusReceiver und nicht als Teil einer HTTP-Anfrage.

Das Objekt someDataObject wird höchstwahrscheinlich ein Objekt aus Ihrer Datenbank sein, so dass es in der Datenbank gespeichert werden kann.

Schließlich kann der Teil, in dem Sie den Benutzer über die durchgeführte Aktion mit den Daten benachrichtigen müssen, auf verschiedene Arten passieren.

Im Allgemeinen ist es ziemlich einfach, alle paar Sekunden einen AJAX-Aufruf an eine HTTP-API auf dem Webserver auszuführen, um nach einer gültigen Antwort zu suchen.

Auf der Browser-Seite, könnte dies so einfach sein wie:


var timer = setInterval(function(){ 

    $.ajax({ 
    url: "/api/check-status", 
    success: function(data){ 
     if (data.complete){ 
     clearInterval(timer); 
     doSomeOtherWork(data); 
     } 
    }) 
    }); 

}); 

und wieder in den Express-App, die Handhabung "/ api/Check-Status", würden Sie das gleiche "someDataObject" Modell verwenden um den Status zu überprüfen:


var someDataObject = require("someDataObject"); 

var router = new express.Router(); 
router.get("/", checkStatus); 

function checkStatus(req, res, next){ 

    someDataObject.load(function(err, someData){ 
    if (err) { return next(err); } 

    res.json({ 
     complete: (someData.status === "complete"), 
     data: someData.data 
    }); 

    }); 

} 

Dies sollte hoffentlich Sie auf den richtigen Weg bringen. Es gibt natürlich viele Details, die ich weggelassen habe, aber hoffentlich kannst du die fehlenden Teile ausfüllen.

...

P. S .: behandle ich all dies, mit Ausnahme des Browser für Status-Updates auf einem Timer überprüft, in meiner RabbitMQ 4 Devs Ausbildung. Es ist ein komplettes Paket, um mit RabbitMQ und Node.js zu beginnen.

+0

es ist ein netter Ansatz, ich denke, dass es mit Pub/Sub-Muster statt Pooling gemischt werden könnte. – Sebastian

Verwandte Themen