Actualización para Erlang 19+
Considere el uso de la nueva conducta gen_statem
. Este comportamiento admite la generación de eventos internos al FSM:
La función de estado puede insertar eventos utilizando la acción() próximo_evento y dicho evento se inserta como el siguiente para presentar a la función de estado. Es decir, como si fuera el evento entrante más antiguo. Un event_type() interno dedicado se puede usar para tales eventos, haciendo que sea imposible confundirlos con eventos externos.
La inserción de un evento reemplaza el truco de invocar sus propias funciones de manejo de estado a las que a menudo tendría que recurrir, por ejemplo, gen_fsm para forzar el procesamiento de un evento insertado antes que otros.
Utilizando el action functionality en ese módulo, puede asegurarse de que su evento se genera en init
y siempre manejado antes de que los acontecimientos externos, especialmente mediante la creación de una acción next_event
en su función init
.
Ejemplo:
...
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) ->
...
...
respuesta Antiguo
Al diseñar un gen_server
por lo general, tiene la opción de realizar acciones en tres estados diferentes:
- al poner en marcha, en
init/1
- Al ejecutar, en cualquier función
handle_*
- Cuando se detenga, en
terminate/2
Una buena regla de oro es para ejecutar las cosas en las funciones de manejo al actuar sobre un evento (llamar, yeso, mensaje, etc.). Las cosas que se ejecutan en init no deben esperar a los eventos, para eso sirven las devoluciones de llamada.
Por lo tanto, en este caso particular, se genera un tipo de evento "falso". Diría que parece que el gen_server
siempre quiere iniciar el inicio del supervisor. ¿Por qué no solo hacerlo directamente en init/1
? ¿Existe realmente un requisito para poder manejar otro mensaje en el medio (el efecto de hacerlo en el handle_info/2
en su lugar)? Esa ventana es increíblemente pequeña (el tiempo entre el inicio del gen_server
y el envío del mensaje al self()
) por lo que es muy poco probable que suceda.
En cuanto al punto muerto, realmente recomendaría no llamar a su propio supervisor en su función init. Eso es solo una mala práctica. Un buen patrón de diseño para iniciar el proceso de trabajo sería un supervisor de nivel superior, con un gerente y un supervisor de trabajador debajo. El gerente comienza trabajadores mediante una llamada al supervisor del trabajador:
[top_sup]
| \
| \
| \
man [work_sup]
/| \
/ | \
/ | \
w1 ... wN
No recomendaría mover cosas a init/1 simplemente porque generalmente se repite el código. Claro, podríamos extraerlo a la función interna, pero luego el código en handle_call es menos legible. – user425720
Bueno, si es código repetido, lo pondría en una función y luego lo llamaría desde 'init/1' y su' handle_call/3' o 'handle_cast/2'. Veo que las llamadas a funciones son mucho más legibles que el envío de mensajes a 'self()'. –