Пишу некую систему на erlang'е, осваиваю язык. Столкнулся с одной проблемой, для которой пока не могу придумать удовлетворяющего меня решения.
В чем суть проблемы: обработкой данных в приложении занимается группа процессов. Большинство процессов представляют из себя машины состояний на основе gen_fsm, конечных состояний работы процесса может быть несколько (например, "операция завершилась успешно", "операцию нельзя выполнить для текущих условий" и т.д.). При этом каждый процесс универсален, то есть он выполняет какую-то вполне определенную задачу, определены контракты на входные и выходные параметры, а его результатами могут воспользоваться произвольные процессы, и эти связи определяет программист, конструируя общую схему взаимодействия процессов (очень напоминает dependency injection). Вопрос: как лучше организовать передачу событий между процессами, как правильно реализовать точки соприкосновения между ними?
Сначала я хотел использовать для этого gen_event. То есть, процессу при старте передается пид EventMgr'а, и когда процесс дойдет до какого-нибудь конечного состояния, то он просто будет вызывать gen_event:notify(EventMgr, ...). Соответственно, все потребители результатов работы этого процесса просто будут регистрировать свои обработчики в EventMgr'е. Схема красивая и архитектурно мне нравится, но у нее есть и свои минусы. Во-первых, для каждого процесса-потребителя придется писать отдельный модуль обработчика событий (behaviour(gen_event)), а может даже и не один. Кроме того, функционал gen_event для меня избыточен, fault tolerance не нужен, так как большинство обработчиков будут просто сводиться к gen_fsm:send_event(...).
Следующим решением было просто написать свой модуль, реализующий подписку на события. Модуль будет позволять сформировать список обработчиков, привязанных к определенным типам событий и вызывать их прямо в контексте процесса, который сгенерирует событие. Как-то так:
Запуск процесса с передачей ему информации о подписчиках (event_handler — мой самописный модуль):
Handlers = event_handler:add(handler2,
event_handler:add(handler1,
event_handler:create())),
Config = [
{param1, value1},
....
{handlers, Handlers}],
some_process:start(Config).
Вызов обработчика внутри процесса:
some_state(Event, State) ->
event_handler:notify(State#state.handlers).
Пока я склоняюсь к этому варианту.
Какие еще есть варианты связывания процессов в erlang'е? Может я вообще иду по неправильному пути?