Временные процессы gen_server и обновление pids - PullRequest
2 голосов
/ 14 ноября 2010

В настоящее время я изучаю Эрланг на приемлемом клипе, но у меня есть вопрос о gen_server с супервизорами. Если процесс gen_server завершается сбоем и последовательно перезапускается супервизором, он получает новый pid. А что если я хочу, чтобы другие процессы ссылались на этот процесс через Pid? Какие хорошие идиоматические способы «обновить» Pid в этих процессах?

В качестве упражнения с некоторым практическим приложением я пишу сервер блокировки, где клиент может запросить блокировку с помощью произвольного ключа. В идеале я хотел бы, чтобы отдельные процессы обрабатывали блокировку и освобождение определенной блокировки, идея в том, что я могу использовать аргумент timeout в gen_server, чтобы завершить процесс, если никто не запросил его после N количества времени, так что только в настоящее время соответствующие замки останутся в памяти. Теперь у меня есть процесс каталога, который отображает имя блокировки на процесс блокировки. Когда процесс блокировки завершается, он удаляет блокировку из каталога.

Меня интересует, как справиться со случаем, когда клиент запрашивает блокировку, когда процесс блокировки находится в середине завершения. Он еще не отключился, так что нюхать, что пид жив, не сработает. Процесс блокировки еще не достиг условия, которое удаляет его из каталога.

Есть ли лучший способ справиться с этим?

EDIT

В настоящее время существует два gen_servers: «каталог», который поддерживает таблицу ETS из LockName -> Lock Process, и «серверы блокировки», которые динамически добавляются в дерево контроля с помощью start_child. В идеале я хотел бы, чтобы каждый сервер блокировки обрабатывал разговоры с клиентами напрямую, но меня беспокоит сценарий запроса на получение / освобождение, который выдается с вызовом или приведением, когда процесс находится в середине сбоя (и поэтому не отвечает к сообщению).

Начиная с {local} или {global} не будет работать, поскольку их может быть N.

Ответы [ 3 ]

5 голосов
/ 15 ноября 2010

Хитрость в том, чтобы назвать процесс и не ссылаться на него по его pid.Обычно у вас есть 3 варианта:

  • Используйте зарегистрированные имена.Это то, что предлагает andreypopp.Вы ссылаетесь на сервер по его зарегистрированному имени. локально зарегистрированные имена должны быть атомами, что может несколько ограничить вас. глобально зарегистрированные имена не имеют этого ограничения, вы можете зарегистрировать любой термин.

  • Супервизор знает Pid.Спроси это.Вам нужно будет передать PID супервизора процессу.

  • В качестве альтернативы, используйте приложение gproc (существует в http://github.com).. Это позволяет вам создать общий реестр процессов - вымог бы сделать это с помощью ETS, но украл бы хороший код, а не реализовал себя.

pid можно использовать, если все процессы являются частью одного и того же дерева контроля.означает смерть других. Таким образом, переработка Пидс не имеет значения.

4 голосов
/ 14 ноября 2010

Не обращайтесь к процессу gen_server по pid.

Вы должны предоставить API для вашего gen_server через функции gen_server:call/2 или gen_server:call/3.Они принимают ServerRef в качестве первого аргумента, который может быть Name | {Name,Node} | {global,GlobalName} | pid().Итак, ваш API будет выглядеть так:

lock(Key) -> gen_server:call(?MODULE, {lock, Key}). release(Key) -> gen_server:call(?MODULE, {release, Key}).

Обратите внимание, что этот API определен в том же модуле, что и ваш gen_server, и я предполагаю, что вы запускаете свой сервер с чем-то вроде: gen_server:start_link({local, ?MODULE}, ?MODULE, [], [])

Таким образом, ваши методы API могут искать сервер не по pid, а по имени сервера, равному ?MODULE.

Для получения дополнительной информации см. gen_server документацию .

1 голос
/ 15 ноября 2010

Вы можете полностью избежать использования процесса «lock_server», используя API «erlang: monitor / demonitor».

Когда клиент запрашивает блокировку, вы запускаете блокировку .. и выполняете erlang: монитор на клиенте .. Это вернет вам ссылку на монитор. Затем вы можете сохранить эту ссылку вместе со своей блокировкой. Вся прелесть в том, что ваш сервер каталогов будет уведомлен, когда клиент умрет.Тайм-аут в клиенте.

Вот фрагмент кода, который я недавно написал. https://github.com/xslogic/phoebus/blob/master/src/table_manager.erl

По сути, table_manager - это процесс, который выдает клиенту блокировку определенного ресурса таблицы.. если клиент умрет, таблица возвращается в пул ..

...