RabbitMQ se întâmplă să fie cea mai ușoară și mai performantă platformă de broker de mesaje care folosește protocolul AMQ existent astăzi. Folosirea acestuia într-o arhitectură de microservicii se traduce prin câștiguri masive de performanță, precum și prin promisiunea fiabilității.

În acest ghid, vom explora elementele de bază ale utilizării RabbitMQ cu Node.js.

Teorie

La nivelul său de bază, în mod ideal ați avea două servicii diferite care interacționează între ele prin Rabbit – a editor și a abonat.

Un editor împinge de obicei mesajele către Rabbit, iar un abonat ascultă aceste mesaje și execută cod pe baza acestor mesaje.

Rețineți că pot fi ambele în același timp – un serviciu poate publica mesaje către Rabbit și poate consuma mesaje în același timp, ceea ce permite proiectarea unor sisteme cu adevărat puternice.

Acum un editor publică de obicei mesaje cu un cheie de rutare la ceva numit an schimb valutar. Un consumator ascultă un coadă pe același schimb, legat de cheia de rutare.

În termeni arhitecturali, platforma dvs. ar utiliza un singur schimb de iepuri, iar diferite tipuri de joburi / servicii ar avea propriile chei de rutare și cozi, pentru ca pub-sub să funcționeze eficient.

Mesajele pot fi șiruri; pot fi, de asemenea, obiecte native – bibliotecile client AMQP fac greutatea mare de a converti obiecte dintr-o limbă în alta. Și da, asta înseamnă că serviciile pot fi scrise în diferite limbi, atât timp cât sunt capabile să înțeleagă AMQP.

Noțiuni de bază

Vom găti un exemplu foarte simplu în care un script de editor publică un mesaj către Rabbit, conținând o adresă URL, iar un script de consum ascultă pe Rabbit, preia URL-ul publicat, îl apelează și afișează rezultatele. Puteți găsi eșantionul finalizat pe Github.

În primul rând, să inițializăm un proiect npm:

$ npm init

Poți oricând să lovești Enter până la capăt și utilizați opțiunile implicite – sau le puteți completa.

Acum, să instalăm pachetele de care avem nevoie. Vom folosi Testoasa pentru a interacționa cu RabbitMQ. De asemenea, vom folosi nod-cron pentru a programa publicarea efectivă a mesajelor.

$ npm install --save tortoise node-cron

Acum package.json ar trebui să arate foarte mult așa:

{
  "name": "freecodecamp-guides-rabbitmq-tortoise",
  "version": "1.0.0",
  "description": "Sample code to accompany the FreeCodeCamp guide on async messaging with RabbitMQ and Tortoise.",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/rudimk/freecodecamp-guides-rabbitmq-tortoise.git"
  },
  "keywords": [
    "rabbitmq",
    "tortoise",
    "amqp"
  ],
  "author": "Rudraksh M.K.",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/rudimk/freecodecamp-guides-rabbitmq-tortoise/issues"
  },
  "homepage": "https://github.com/rudimk/freecodecamp-guides-rabbitmq-tortoise#readme",
  "dependencies": {
    "node-cron": "^1.2.1",
    "tortoise": "^1.0.1"
  }
}

Acum suntem cu toții pregătiți. Să creăm mai întâi un editor.

const Tortoise = require('tortoise')
const cron = require('node-cron')

const tortoise = new Tortoise(`amqp://rudimk:YouKnowWhat@$localhost:5672`)

După import tortoise și node-cron, am continuat și am inițializat o conexiune la RabbitMQ În continuare, să scriem o funcție rapidă și murdară care publică un mesaj către Rabbit:

function scheduleMessage(){
    let payload = {url: 'https://randomuser.me/api'}
    tortoise
    .exchange('random-user-exchange', 'direct', { durable:false })
    .publish('random-user-key', payload)
}

Este destul de simplu. Am definit un dicționar care conține o adresă URL pentru RandomUser.me API, care este apoi publicat în random-user-exchange schimb pe RabbitMQ, cu random-user-key cheie de rutare.

După cum sa menționat mai devreme, cheia de rutare este cea care determină cine ajunge să consume un mesaj. Acum, să scriem o regulă de programare, pentru a publica acest mesaj la fiecare 60 de secunde.

cron.schedule('60 * * * * *', scheduleMessage)

Și editorul nostru este gata! Dar chiar nu este bine fără un consumator să consume aceste mesaje! Dar mai întâi, avem nevoie de o bibliotecă care poate apela adresa URL din aceste mesaje. Personal, folosesc superagent: npm install --save superagent.

Acum in consumer.js:

const Tortoise = require('tortoise')
const superagent = require('superagent')

const tortoise = new Tortoise(`amqp://rudimk:YouKnowWhat@$localhost:5672`)

Apoi, să scriem o funcție asincronizată care apelează o adresă URL și afișează rezultatul:

async function getURL(url){
	let response = await superagent.get(url)
	return response.body
}

Este timpul să scrieți codul pentru a consuma mesaje:

tortoise
.queue('random-user-queue', { durable: false })
// Add as many bindings as needed 
.exchange('random-user-exchange', 'direct', 'random-user-key', { durable: false })
.prefetch(1)
.subscribe(function(msg, ack, nack) {
  // Handle 
  let payload = JSON.parse(msg)
  getURL(payload['url']).then((response) => {
    console.log('Job result: ', response)
  })
  ack() // or nack()
})

Aici, am spus tortoise pentru a asculta random-user-queue, care este legat de random-user-key pe random-user-exchange. Odată ce un mesaj este primit, sarcina utilă este recuperată de la msg, și este transmis de-a lungul getURL funcție, care la rândul său returnează o Promisiune cu răspunsul JSON dorit de la RandomUser API.

Concluzie

Simplitatea asociată utilizării RabbitMQ pentru mesagerie este de neegalat și este foarte ușor să veniți cu modele de microservicii complexe, cu doar câteva linii de cod.

Cea mai bună parte este că logica din spatele mesageriei nu se schimbă într-adevăr între limbi – Crystal sau Go sau Python sau Ruby funcționează cu Rabbit cam în același mod. Acest lucru înseamnă că puteți avea servicii scrise în diferite limbi, toate comunicând între ele fără efort, permițându-vă să utilizați cea mai bună limbă pentru job.