Всем доброго времени суток. Я недавно начал применять node js в реальных проектах, но все еще часто натыкаюсь на грабли, в первую очередь архитектурные, особенно после очень тесного общения с PHP, где для меня все просто и так знакомо (получил запрос - обработал - отдал ответ, никакой асинхронности, коллбэков и т.п.).
Я разрабатываю приложение, позволяющее руководству колл центра управлять его работой.
В приложении есть два модуля, Ami для взаимодействия с Asterisk Manager Interface (телефония) и ApiServer для приема запросов от пользователей (грубо говоря fastify с прописанными маршрутами).
Я решил жестко не связывать модули друг с другом, используя require a в b и require b в a, а настроить связь через pub sub.
В результате я получил два совершенно автономных модуля, которые ничего не знают друг о друге и занимаются своими делами, но я столкнулся с огромным подводным камнем.
Если старший смены захочет убрать агента из очереди все отработает замечательно, на ApiService придет запрос, он отправит сообщение, Ami примет сообщение и отправит в астериск команду на удаление агента.
Но что если старший смены захочет получить статус агента, глубину очереди и т.п?
Тогда Api серверу нужно не просто отправить сообщение в Ami, а получить на него ответ и отдать его клиенту в контексте обработки этого запроса.
И тут пошли хождения по мукам, решением "в лоб" было зарекваерить Ami в ApiService и вызывать метод из него, но оно мне не нравилось потому что тогда нарушало принцип независимости модулей друг от друга.
Я придумал другое решение: при запросе на сервер Api я генерирую uuid запроса и помещаю коллбэк, в котором происходит отдача ответа пользователю в специальный пул, после чего отправляю сообщение в модуль Ami.
Обработчик в модуле Ami вытаскивает данные из астериска, после чего отправляет их, вместе с uuid запроса в специальный канал pub sub, на который подписан пул в модуле Api и который при поступлении сообщения вызывает связанный с этим uuid коллбэк.
Работать то оно работает, но из-за отсутствия опыта я не могу понять насколько такое решение приемлимо и оптимально.
В качестве альтернативы я написал свой модуль в котором модуль может запросить данные у другого:
let response = await ModuleRequest.request('channel', 'topic', {
data: {},
timeout: 1000
});
А другой модуль может ответить ему:
ModuleRequest.on('channel', 'topic', (data) => {
//SomeActions
return 'some data';
});
Но опять же, насколько такой подход удачен с точки зрения архитектуры? Как обычно решаются подобные задачи, подскажите пожалуйста.