Estrategias para trabajar con Supervisor

Más sobre las child-specs y las estrategias para lanzar supervisores, y cómo crear supervisores usando módulos separados.

Los árboles de supervisión en Elixir son estructuras jerárquicas que nos permiten gestionar procesos de forma robusta y ordenada. A diferencia de lo que podríamos pensar inicialmente, un supervisor no solo supervisa procesos tipo GenServer o workers, sino que también puede supervisar a otros supervisores, formando así un árbol con múltiples niveles.

Cuando lanzamos un supervisor, normalmente utilizamos la función start_link con dos parámetros: una lista de hijos y una lista de opciones. Es importante destacar que existen diferentes versiones de esta función, como start_link/2 y start_link/3, que tienen comportamientos distintos y que exploraremos más adelante. En cuanto a la lista de hijos, aunque a menudo pasamos una tupla simple con el módulo y sus parámetros, esta es en realidad una forma simplificada. La especificación completa de un hijo es un mapa que puede contener muchos más detalles, como el identificador del proceso, la función de inicio, la estrategia de reinicio, entre otros.

Por ejemplo, la especificación completa de un hijo incluye un campo start, que es una tupla con el módulo, la función a invocar (por defecto start_link) y los parámetros que se le pasan. También incluye un campo id, que suele ser un átomo que identifica al proceso. Aunque podemos construir estos mapas manualmente, Elixir nos facilita la vida con la función child_spec que implementan los módulos como GenServer, la cual transforma una forma simplificada en la estructura completa necesaria para el supervisor.

Un aspecto fundamental en los árboles de supervisión es la estrategia de reinicio que se utiliza cuando un proceso falla. La estrategia más común es one_for_one, que reinicia únicamente el proceso que ha fallado. Sin embargo, existen otras dos estrategias importantes. La estrategia one_for_all reinicia todos los procesos supervisados si uno de ellos falla, similar a cuando en una clase entera se castiga a todos por la acción de uno solo. Por último, la estrategia rest_for_one reinicia el proceso que falló y todos los procesos que están listados después de él en la lista de hijos, lo que hace que el orden en que declaramos los hijos sea crucial.

Cuando un proceso debe detenerse, el supervisor envía una señal de salida mediante la función Process.exit/2. Esta señal puede ser capturada por el proceso si implementa un trap para manejarla, lo que es útil para liberar recursos como conexiones a bases de datos o sockets antes de terminar. Si el proceso no responde a tiempo, se le envía una señal de kill, que no puede ser atrapada y termina el proceso inmediatamente.

Además de supervisar procesos individuales, podemos crear módulos que actúen como supervisores reutilizables. Para ello, usamos use Supervisor en el módulo, lo que nos permite implementar los callbacks necesarios para definir la lista de hijos y la estrategia de reinicio. Estos módulos supervisores pueden ser anidados, formando árboles de supervisión más complejos y organizados, donde un supervisor puede supervisar a otros supervisores.

Para que un módulo supervisor sea compatible con esta estructura, debe implementar la función start_link/1 que inicie el supervisor y devuelva la tupla {:ok, pid}. Dentro de esta función, declaramos los hijos y la estrategia de reinicio utilizando Supervisor.start_link/2. Esto facilita la reutilización y composición de supervisores en aplicaciones Elixir más grandes.

Por último, es importante tener en cuenta que el callback init/1 debe ser implementado en los módulos supervisores para definir la configuración del supervisor, aunque dependiendo de cómo llamemos a start_link, esto puede variar. Este tema se profundizará más adelante, pero es esencial para entender cómo configurar correctamente nuestros supervisores.

En definitiva, trabajar con árboles de supervisión en Elixir implica comprender cómo definir correctamente los hijos con sus especificaciones completas, elegir la estrategia de reinicio adecuada según las necesidades de nuestra aplicación y estructurar nuestros supervisores en módulos reutilizables que permitan construir jerarquías robustas y mantenibles.

Lista de reproducción
  1. 1
    Cómo crear procesos
    11 minutos
  2. 2
    Cómo pasar mensajes entre procesos
    13 minutos
  3. 3
    Diccionario de un proceso y mantener un estado
    15 minutos
  4. 4
    Cómo enlazar procesos para detectar fallos
    13 minutos
  5. 5
    Cómo monitorizar procesos
    10 minutos
  6. 6
    ¿Qué es un GenServer?
    15 minutos
  7. 7
    Cómo enviar mensajes con un GenServer
    19 minutos
  8. 8
    Control de errores y gestión de un GenServer
    19 minutos
  9. 9
    Cómo renombrar procesos
    11 minutos
  10. 10
    Cómo crear un Supervisor Tree
    17 minutos
  11. 11
    Estrategias para trabajar con Supervisor
    18 minutos
  12. 12
    Estrategias para crear un Supervisor
    11 minutos
  13. 13
    Resumen sobre procesos OTP
    12 minutos
  14. 14
    Cómo usar Application
    12 minutos
  15. 15
    Ejemplo de Application con hijos
    14 minutos