У меня есть два приложения NodeJs Express, связанные с двумя разными базами данных, для удобства назовем первое приложение A и второе B, оба связаны с одним и тем же экземпляром Redis с помощью Ioredis.
A не может напрямую получить доступ к базе данных B, ему необходимо выполнить HTTP-запрос, чтобы получить данные из базы данных B.
В конечной точке приложения А мне нужно проверить значение из базы данных приложения Б, это конечная точка с очень высоким трафиком и сотнями запросов в минуту, я не могу просто выполнить http-запрос для получения данных из приложения Б, потеря производительности. будет слишком высоким.
Решение, которое я нашел, — это redis Pub/Sub, я могу зарегистрироваться с двух каналов в приложении A и B.
Если требуемое значение отсутствует в Redis, я буду использовать два канала:
Один канал для отправки сообщений из канала приложения A в приложение B для сохранения объектов из базы данных в Redis.
Второй канал для отправки сообщений из приложения B в приложение A, чтобы сохранить и вернуть объект, полученный из базы данных.
Мой вопрос: есть ли способ в вызове первого канала приложения A ожидать ответного ответа от приложения B через второй канал?
Может ли что-то подобное работать?
Базовый POC
async function main() {
await redis.subscribe("get-company", (err, count) => {
if (err) console.error(err.message);
});
redis.on("message", (channel, message) => {
console.info(`Received first message from ${channel} channel.`);
redis.publish('send-company', 'test')
console.info(message);
});
main2()
}
async function main2() {
await redis2.subscribe("get-company", (err, count) => {
if (err) console.error(err.message);
});
redis2.publish('get-company', 'test').then(async (data)=>{
console.info('first send completed');
redis2.on("message", (channel, message) => {
console.info(`Received response from ${channel} channel.`);
console.info(message);
redis2.unsubscribe();
})
})
}
main()





Вы можете сделать что-то вроде ниже. Обратите внимание, что это базовый макет. Пожалуйста, обновите логику в соответствии с вашими потребностями.
Первым шагом было бы разделить два приложения для ясности.
В приложении А:
// import necessary modules as per your need
// import necessary modules as per your need
const Redis = require('ioredis');
const redisAppASub = new Redis();
const redisAppAPub = new Redis();
async function appA(){
await redisAppASub.subscribe("send-company", (err, count) => {
if (err) console.error(err?.message);
});
redisAppASub.on("message", async (channel, message) => {
if (channel === "send-company") {
console.info(message);
// handle the received message here
// unsubscribe if required
// redisAppA.unsubscribe();
}
});
// Possible solution for the query ["My question is, is there a way in the application A first channel call to await a return response from application B through the second channel ?"]
async function requestDataFromAppB(){
return new Promise((resolve, reject) => {
redisAppAPub.publish("get-company", "requestDBData", (err) => {
if (err) return reject(err);
console.info("request sent to Application B");
});
// Temporary subscription to listen and resolve the response
redisAppASub.once("message", (channel, message) => {
if (channel == "send-company"){
resolve(message)
}
});
});
}
// call the requestDataFromAppB and get the response
const response = await requestDataFromAppB();
console.info(response, " <<--------- response received from Application B");
}
// call as per your need
appA().catch(err => console.error(`Application A error: ${err?.message}`));
В приложении Б:
// import necessary modules as per your need
const Redis = require('ioredis');
const redisAppBSub = new Redis();
const redisAppBPub = new Redis();
async function appB(){
console.info("Application B is starting...");
await redisAppBSub.subscribe("get-company", (err, count) => {
if (err) console.error(err?.message);
});
redisAppBSub.on("message", async (channel, message) => {
if (channel == "get-company" && message == "requestDBData"){
const dbData = await fetchDataFromDatabase();
console.info(dbData, ` <<----- dbData`);
redisAppBPub.publish("send-company", dbData, (err) => {
if (err) console.info(err?.message)
console.info("response sent to Application A")
});
}
});
async function fetchDataFromDatabase() {
// Your data fetching logic here
// Simulate fetching data with a delay using a Promise
return new Promise((resolve) => {
setTimeout(() => {
resolve(JSON.stringify({data: "data from database"}));
}, 5000);
});
}
}
// call as per your need
appB().catch(err => console.error(`Application B error: ${err?.message}`));
Не за что. Я обновил код и добавил два соединения Redis. Один для подписки, а другой для публикации, так как у меня возникали ошибки. Поэтому, пожалуйста, имейте это в виду и проверяйте тоже со своей стороны. Приятного кодирования :)