Обновление для Эрланга 19+
Рассмотрите возможность использования нового поведения gen_statem
. Это поведение поддерживает генерацию событий внутри FSM:
Функция состояния может вставлять события с помощью action() next_event, и такое событие вставляется как следующее для представления функции состояния. То есть, как будто это самое старое входящее событие. Для таких событий можно использовать специальный внутренний event_type(), что делает невозможным их ошибочное принятие за внешние события.
Вставка события заменяет прием вызова ваших собственных функций обработки состояния, к которым вам часто приходилось бы прибегать, например, в gen_fsm, чтобы принудительно обработать вставленное событие раньше других.
Используя функционал действия в этом модуле, вы можете убедиться, что ваше событие сгенерировано в init
и всегда обрабатывается перед любыми внешними событиями, в частности, путем создания действия next_event
в вашей функции init
.
Пример:
...
callback_mode() -> state_functions.
init(_Args) ->
{ok, my_state, #data{}, [{next_event, internal, do_the_thing}]}
my_state(internal, do_the_thing, Data) ->
the_thing(),
{keep_state, Data);
my_state({call, From}, Call, Data) ->
...
...
Старый ответ
При разработке gen_server
у вас обычно есть возможность выполнять действия в трех разных состояниях:
- При запуске в
init/1
- При запуске в любой
handle_*
функции
- При остановке в
terminate/2
Хорошее эмпирическое правило — выполнять действия в функциях обработки при воздействии на событие (вызов, приведение, сообщение и т. д.). Вещи, которые выполняются в init, не должны ждать событий, для чего нужны обратные вызовы дескрипторов.
Итак, в данном конкретном случае генерируется своего рода поддельное событие. Я бы сказал, что gen_server
всегда хочет инициировать запуск супервизора. Почему бы просто не сделать это прямо в init/1
? Действительно ли требуется иметь возможность обрабатывать другое сообщение между ними (вместо этого эффект выполнения в handle_info/2
)? Это окно невероятно маленькое (время между запуском gen_server
и отправкой сообщения self()
), поэтому маловероятно, что это вообще произойдет.
Что касается тупиковой ситуации, я бы очень не советовал вызывать вашего собственного руководителя в вашей функции инициализации. Это просто плохая практика. Хорошим шаблоном проектирования для запуска рабочего процесса будет один супервайзер верхнего уровня с менеджером и рабочим супервайзером ниже. Менеджер запускает воркеров, вызывая супервайзера воркеров:
[top_sup]
| \
| \
| \
man [work_sup]
/ | \
/ | \
/ | \
w1 ... wN
person
Adam Lindberg
schedule
19.05.2011