This is a continuation of the article “ Writing the first microservice on Node.js with communication via RabbitMQ ”, which was well received by users of the habr.
In this article I will talk about how to properly communicate between microservices so that microservices remain isolated.
Why do I need to communicate between microservices? You use one database, read what you want from there - business!
No, you can't do that. The concept of microservices is that they are isolated from each other, no one knows anything about anyone (practically). Most likely, in the future, when the system starts to grow, you will want to expand the functionality and you will need to communicate between microservices: for example, the user has bought the product, which means you need to send a notice of sale to the seller.
Suppose there is a monolithic application in which there are several controllers:
One day our database is falling: now we can not get any products, discounts, blog articles or users. The site is completely unavailable, customers can not enter, the business is losing profits.
What will happen in microservice architecture?
In another universe, on the same day, the microservice user database falls, it becomes inaccessible: users cannot log out, register and log in. It would seem that everything is bad and the business also loses profit, but no: potential buyers can look at the available products, read the company's blog, find discounts.
Due to the fact that each microservice has its own database, side effects become much smaller.
This is called gradual degradation .
In a large application, it is very difficult to focus on one task, because by changing some small middleware, you can break down some kind of controller. Want to use the new client for redis - no, you can't, the controller that we wrote three years ago uses version 0.1.0. Want to finally use the new features of Node.js 10? Or maybe 12? Sorry, but version 6 is used in the monolith.
Since we started talking about the example of “a user bought a product, we send a notice of sale to the seller,” then we implement it.
The scheme is as follows:
$ npm i micromq@1 -S
const Gateway = require('micromq/gateway'); // const gateway = new Gateway({ microservices: ['market'], rabbit: { url: process.env.RABBIT_URL, }, }); // market gateway.post('/market/buy/:id', (req, res) => res.delegate('market')); // gateway.listen(process.env.PORT);
A gateway in our country consists of only one endpoint, but this is enough for example and training.
const MicroMQ = require('micromq'); const WebSocket = require('ws'); // const app = new MicroMQ({ name: 'notifications', rabbit: { url: process.env.RABBIT_URL, }, }); // const ws = new WebSocket.Server({ port: process.env.PORT, }); // const clients = new Map(); // ws.on('connection', (connection) => { // connection.on('message', (message) => { // , . // try/catch, json! const { event, data } = JSON.parse(message); // 'authorize' if (event === 'authorize' && data.userId) { // clients.set(data.userId, connection); } }); }); // , // ! ws.on('close', ...); // notify, app.action('notify', (meta) => { // , 400 if (!meta.userId || !meta.text) { return [400, { error: 'Bad data' }]; } // const connection = clients.get(meta.userId); // , 404 if (!connection) { return [404, { error: 'User not found' }]; } // connection.send(meta.text); // 200 return { ok: true }; }); // app.start();
Here we are raising a web-server and microservice at the same time to receive requests for both web-based and RabbitMQ.
The scheme is as follows:
authorize
event with his userId inside const MicroMQ = require('micromq'); const { Items } = require('./api/mongodb'); // const app = new MicroMQ({ name: 'market', rabbit: { url: process.env.RABBIT_URL, }, }); // app.post('/market/buy/:id', async (req, res) => { const { id } = req.params; // const item = await Items.findOne({ id, isSold: false }); // , 404 if (!item) { res.status(404).json({ error: 'Item not found', }); return; } // , , await Items.updateOne({ id, }, { $set: { isSold: true, }, }); // , req.app.ask('notifications', { server: { action: 'notify', meta: { userId: item.sellerId, text: JSON.stringify({ event: 'notification', data: { text: `Item #${id} was sold!`, }, }), }, }, }) // , .catch(err => console.log('Cannot send message via notifications microservice', err)); // , res.json({ ok: true, }); }); // app.start();
The scheme is as follows:
{ ok: true }
$ PORT=9000 node ./src/gateway.js $ PORT=9001 node ./src/notifications.js $ MONGODB_URL=mongodb://localhost:27017/my-super-microservice node ./src/market.js
Source: https://habr.com/ru/post/447250/
All Articles