125 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| ---
 | ||
| title: Async messaging with RabbitMQ and Tortoise
 | ||
| localeTitle: Асинхронные сообщения с помощью RabbitMQ и Tortoise
 | ||
| ---
 | ||
| RabbitMQ - это самые простые и эффективные платформы для брокерских сообщений, использующие сегодня протокол AMQ. Использование его в архитектуре микросервиса приводит к увеличению производительности, а также к надежности. В этом руководстве мы рассмотрим основы использования RabbitMQ с Node.js.
 | ||
| 
 | ||
| ## теория
 | ||
| 
 | ||
| На самом базовом уровне вы идеально должны иметь две разные службы, взаимодействующие друг с другом через Rabbit - _издателя_ и _подписчика_ . Издатель обычно передает сообщения Кролику, и абонент слушает эти сообщения и выполняет код на основе этих сообщений. Обратите внимание, что они могут быть одновременно одновременно - служба может публиковать сообщения в Rabbit и потреблять сообщения одновременно, что позволяет создавать действительно мощные системы.
 | ||
| 
 | ||
| Теперь издатель обычно публикует сообщения с _ключом маршрутизации_ к тому, что называется _обменом_ . Потребитель слушает _очередь_ на том же обмене, привязанный к ключу маршрутизации. В архитектурном плане ваша платформа будет использовать один обмен кролика, а разные виды заданий / сервисов будут иметь свои собственные ключи и очереди маршрутизации, чтобы pub-sub работал эффективно. Сообщения могут быть строками; они также могут быть родными объектами - клиентские библиотеки AMQP делают тяжелый подъем конвертируемых объектов с одного языка на другой. И да, это означает, что услуги могут быть написаны на разных языках, если они способны понимать AMQP.
 | ||
| 
 | ||
| ## Начиная
 | ||
| 
 | ||
| Мы собираемся подготовить очень простой пример, когда скрипт издателя публикует сообщение для Rabbit, содержащее URL-адрес, а потребительский скрипт прослушивает Rabbit, выдает опубликованный URL-адрес, вызывает его и отображает результаты. Вы можете найти готовый образец на [Github](https://github.com/rudimk/freecodecamp-guides-rabbitmq-tortoise) .
 | ||
| 
 | ||
| Сначала давайте инициализируем проект npm:
 | ||
| 
 | ||
| `$ npm init`
 | ||
| 
 | ||
| Вы всегда можете просто нажать `Enter` полностью и использовать параметры по умолчанию - или вы можете их заполнить. Теперь давайте установим нужные нам пакеты. Мы будем использовать [Tortoise](https://www.npmjs.com/package/tortoise) , чтобы взаимодействовать с RabbitMQ. Мы также будем использовать [node-cron](https://www.npmjs.com/package/node-cron) , чтобы запланировать фактическую публикацию сообщений.
 | ||
| 
 | ||
| `$ npm install --save tortoise node-cron`
 | ||
| 
 | ||
| Теперь ваш `package.json` должен выглядеть так:
 | ||
| ```
 | ||
| { 
 | ||
|   "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 MK", 
 | ||
|   "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" 
 | ||
|   } 
 | ||
|  } 
 | ||
| ```
 | ||
| 
 | ||
| Теперь мы все настроены. Давайте сначала создадим издателя.
 | ||
| 
 | ||
| ```javascript
 | ||
| const Tortoise = require('tortoise') 
 | ||
|  const cron = require('node-cron') 
 | ||
|  
 | ||
|  const tortoise = new Tortoise(`amqp://rudimk:YouKnowWhat@$localhost:5672`) 
 | ||
| ```
 | ||
| 
 | ||
| После импорта `tortoise` и `node-cron` мы пошли вперед и инициализировали соединение с RabbitMQ. Затем, давайте напишем быструю и грязную функцию, которая публикует сообщение для Rabbit:
 | ||
| 
 | ||
| ```javascript
 | ||
| function scheduleMessage(){ 
 | ||
|     let payload = {url: 'https://randomuser.me/api'} 
 | ||
|     tortoise 
 | ||
|     .exchange('random-user-exchange', 'direct', { durable:false }) 
 | ||
|     .publish('random-user-key', payload) 
 | ||
|  } 
 | ||
| ```
 | ||
| 
 | ||
| Это достаточно просто. Мы определили словарь, содержащий URL-адрес для API [RandomUser.me](https://randomuser.me/) , который затем публикуется на `random-user-exchange` на RabbitMQ с помощью `random-user-key` маршрутизации с `random-user-key` [доступом](https://randomuser.me/) . Как упоминалось ранее, ключ маршрутизации определяет, кто получает сообщение. Теперь давайте напишем правило планирования, чтобы опубликовать это сообщение каждые 60 секунд.
 | ||
| 
 | ||
| ```javascript
 | ||
| cron.schedule('60 * * * * *', scheduleMessage) 
 | ||
| ```
 | ||
| 
 | ||
| И наш издатель готов! Но действительно бесполезно, если потребитель не потребляет эти сообщения! Но сначала нам нужна библиотека, которая может вызывать URL-адрес в этих сообщениях. Лично я использую `superagent` : `npm install --save superagent` .
 | ||
| 
 | ||
| Теперь, в `consumer.js` :
 | ||
| 
 | ||
| ```javascript
 | ||
| const Tortoise = require('tortoise') 
 | ||
|  const superagent = require('superagent') 
 | ||
|  
 | ||
|  const tortoise = new Tortoise(`amqp://rudimk:YouKnowWhat@$localhost:5672`) 
 | ||
| ```
 | ||
| 
 | ||
| Далее, давайте напишем функцию async, которая вызывает URL-адрес и отображает результат:
 | ||
| 
 | ||
| ```javascript
 | ||
| async function getURL(url){ 
 | ||
|     let response = await superagent.get(url) 
 | ||
|     return response.body 
 | ||
|  } 
 | ||
| ```
 | ||
| 
 | ||
| Время написания кода для фактического потребления сообщений:
 | ||
| 
 | ||
| ```javascript
 | ||
| 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() 
 | ||
|  }) 
 | ||
| ```
 | ||
| 
 | ||
| Здесь мы сказали `tortoise` прослушивать `random-user-queue` , которая привязана к `random-user-key` при `random-user-exchange` . После получения сообщения полезная нагрузка извлекается из `msg` и передается вместе с функцией `getURL` , которая, в свою очередь, возвращает Promise с требуемым ответом JSON от API RandomUser.
 | ||
| 
 | ||
| ## Вывод
 | ||
| 
 | ||
| Простота, связанная с использованием RabbitMQ для обмена сообщениями, не имеет себе равных, и очень легко придумать действительно сложные микросервисные шаблоны с несколькими строками кода. Лучшая часть заключается в том, что логика обмена сообщениями на самом деле не меняется на разных языках - Crystal или Go или Python или Ruby работают с Rabbit почти так же - это означает, что вы можете иметь услуги, написанные на разных языках, все общающиеся друг с другом без усилий , позволяя вам использовать лучший язык для работы. |