Использование модуля Registry в Elixir 1.4
Одно из нововведений в Elixir 1.4, которого многие с нетерпением ждали, — это модуль Registry. Из этой статьи вы узнаете, как можно извлечь пользу из этого замечательного модуля, который теперь является частью стандартной библиотеки.
Если вы только приступили к изучению Elixir и принципов OTP, то количество идентификаторов процессов (PID) наверняка покажется вам неисчислимым, особенно при использовании REPL (iex). Для модели акторов сотни или даже тысячи выполняемых в системе процессов — обычное дело. Один из способов связаться с этими процессами — отслеживать их при запуске по PID или заданным именам. Модуль Registry предлагает другой способ сделать это без использования внешних библиотек.
Предположим, вы занимаетесь продажей виджетов своим клиентам (далее — пользователям). Перед вами стоит задача разработать интерфейс пользователя (UI) для системы реального времени, чтобы он отображал учётные записи тех, кто разместил заказ в текущий день, и основную информацию по каждой учётной записи. Если пользователь не заказывал ничего в течение 24 часов, то его учётная запись удалялась бы из списка в UI.
Одно из быстрых решений — создать процесс сразу после того, как пользователь разместит заказ и реализовать функцию, которая по прошествии 24 часов удаляла бы процессы, не задействованные в новых заказах. Но как в таком случае понять, с какой учётной записью связан тот или иной процесс? С этой задачей отлично справляется модуль Registry, работающий практически как DNS-поиск по имени, а в нашем случае по account_id
, и предоставляющий ссылку на исполняемый процесс.
Реестр будет своего рода адресной книгой для процессов (изображение © 2010 by Tomasz Sienicki)
Прежде всего нужно будет запустить реестр и присвоить ему имя с помощью функции Registry.start_link
. Далее просто добавим нужный реестр к дереву супервизоров приложения. Обратите внимание на то, что мы создаём реестр :unique
.
Теперь у вас есть свой реестр под названием :account_process_registry
, который будет отслеживать идентификаторы процессов. Остаётся только реализовать функцию, которая будет возвращать кортеж :via
в соответствии с переданным ей значением. GenServer упрощает работу с кортежем :via
и обеспечивает автоматическую привязку имени (account_id
) к процессу.
Функция via_tuple
вместе с модулем Registry позволяют создавать процесс для заданного account_id
и осуществлять последующие вызовы процесса по имени, а не по PID. И больше не придётся иметь дело с «загадочными» PID или разрабатывать собственную систему назначения имён внутри функции start_link
. Чтобы найти процесс среди тысяч других процессов, достаточно будет всего лишь иметь его account_id
.
А что если снова запустить процесс для account_id
№ 5?
Реестр напомнит нам, что процесс для account_id
№ 5 уже отслеживается, о чём будет сигнализировать сообщение :already_started
.
Неплохое начало. Теперь можно программно создавать нужный процесс с именем или идентификатором, не опасаясь того, что процесс для данного идентификатора уже существует: система об этом предупредит. Ещё одно преимущество в том, что, если возникнет ошибка и процесс перезапустится по какой-либо причине, система зарегистрирует новый PID для исходного имени. Стандартная ссылка на определённый PID так бы не сработала.
Что же делать дальше? А дальше останется лишь осуществить вызовы в GenServer и обновить состояние. Возможность идентификации процессов программно на Elixir — отличное решение, позволяющее разработчику больше времени уделить бизнес-логике. Конечно, чтобы передать данные в интерфейс, всё равно придётся реализовать веб-сокет, но сегодня речь не об этом. (Подсказка: рекомендую для создания простых сокетов использовать cowboy).
Если покопаться в примере на Github, то в модуле RegistrySample.AccountSupervisor
можно отыскать несколько полезных функций для взаимодействия с реестром. Функции вроде find_or_create_process/1
можно использовать, чтобы облегчить работу с процессами.
Можете смело адаптировать этот код для своих целей и продолжать изучать возможности Registry!