Как работает Process.monitor/1 и Process.link/1?
В Elixir функции Process.monitor/1 и Process.link/1 используются для организации взаимодействия между процессами, особенно в части наблюдения за их жизненным циклом и обработки их завершения. Они являются фундаментальными примитивами в модели конкурентности Erlang VM (BEAM), на которой работает Elixir.
Process.link/1
Process.link(pid) устанавливает двухстороннюю связь между текущим процессом и процессом с идентификатором pid. Если один из процессов завершится по какой-либо причине (исключение, вызов exit, завершение узла), то связанный с ним процесс получит сигнал об этом завершении. Если он не настроен на обработку сигнала (trap_exit: true), то он тоже завершится с той же причиной.
Пример:
spawn_link(fn ->
raise "ошибка"
end)
Этот процесс упадёт, и текущий процесс (в котором вызван spawn_link) тоже упадёт.
Использование:
- 
Полезно в архитектуре «let it crash», когда процессы связаны логически и один не должен продолжать без другого. 
- 
Часто используется внутри супервизоров. 
- 
Работает синхронно: если pid не существует, сразу вызывает исключение. 
Удаление связи:
Для удаления связи можно использовать Process.unlink(pid).
Process.monitor/1
Process.monitor(pid) устанавливает одностороннее наблюдение за процессом. Если наблюдаемый процесс завершается, наблюдатель получает сообщение вида:
{:DOWN, ref, :process, pid, reason}
В отличие от link, мониторинг не завершает текущий процесс автоматически — он просто получает сообщение, и дальнейшие действия зависят от вашей логики обработки.
Пример:
pid = spawn(fn -> raise "boom" end)
ref = Process.monitor(pid)
receive do
{:DOWN, ^ref, :process, ^pid, reason} ->
IO.puts("Процесс #{inspect pid} завершился с причиной: #{inspect reason}")
end
Использование:
- 
Не требует trap_exit. 
- 
Подходит для задач, где нужно отслеживать, жив ли другой процесс, но не зависеть от него напрямую. 
- 
Используется в Task, GenServer, DynamicSupervisor, Registry и других системных конструкциях. 
Поведение:
- 
Возвращает уникальную ссылку ref, по которой приходит :DOWN. 
- 
Монитор автоматически снимается после получения :DOWN, или его можно снять вручную с помощью Process.demonitor(ref). 
Основные отличия link и monitor
| Характеристика | Process.link/1 | Process.monitor/1 | 
|---|---|---|
| Связь | Двусторонняя | Односторонняя | 
| --- | --- | --- | 
| Влияние на завершение | Падает оба процесса | Только сообщение :DOWN | 
| --- | --- | --- | 
| Обработка | Через trap_exit | Через receive | 
| --- | --- | --- | 
| Используется в | Супервизорах, spawn_link | Task, динамические системы | 
| --- | --- | --- | 
| Удаление | Process.unlink/1 | Process.demonitor/1 | 
| --- | --- | --- | 
| Безопасность | Менее безопасный | Более безопасный | 
| --- | --- | --- | 
Совместное использование
Можно использовать link и monitor вместе, но делать это нужно осознанно. Например, если вы хотите, чтобы процесс был связан (в случае нормальной работы), но при этом могли обрабатывать завершение вручную, а не падать автоматически — тогда можно настроить trap_exit: true и использовать receive.
Обработка падения с trap_exit
defmodule Watcher do
def start do
Process.flag(:trap_exit, true)
pid = spawn_link(fn -> raise "ошибка" end)
receive do
{:EXIT, ^pid, reason} ->
IO.puts("Процесс завершился: #{inspect reason}")
end
end
end
Когда использовать link, а когда monitor
- 
link: если процессы тесно связаны логически, и отказ одного должен завершать другой (например, в OTP-супервизорах). 
- 
monitor: если нужен просто контроль завершения, без риска завершения текущего процесса (например, в асинхронных задачах, отслеживании клиентов в чате, обработке долгоживущих сервисов).