Системный актор

Системный актор — актор, который может обрабатывать ошибки, исходящие от акторов, с которыми установлен линк.

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

Все акторы спаунятся как нормальные. Чтобы актору стать системным, он должен выполнить биф process_flag(trap_exit, true). Это может сделать и посторонний актор: process_flag(Pid, trap_exit, true).

Системный актор, как легко догадаться, имеет важное значение: он не должен рушиться, он должен обрабатывать ошибки.

Чтобы посмотреть, как работает системный актор, создадим сначала просто два слинкованных актора.

-module(razdva).
-export([raz/0]).

raz() ->
    spawn_link(fun() -> math:sqrt(-13) end),
    loop().

loop() ->
    receive
        Mess -> io:format("Got: ~p~n",[Mess]), loop()
    end.

Мы будем спаунить актор raz, а он в свою очередь заспаунит актор dva с помощью атомарной функции spawn_link/1, которая помимо спауна сразу устанавливает линк между двумя акторами: создающим и создаваемым. Второй актор должен моментально рухнуть, потому что пробует извлечь квадратный корень из -13.

1> spawn(razdva, raz, []).
<0.86.0>
=ERROR REPORT==== 25-Dec-2024::15:08:22.587817 ===
Error in process <0.87.0> with exit value:
{badarith,[{math,sqrt,[-13],[{error_info,#{module => erl_stdlib_errors}}]},
           {razdva,'-raz/0-fun-0-',0,[{file,"razdva.erl"},{line,5}]}]}

2> is_process_alive(<0.86.0>).
false

Работает или нет актор raz, мы проверяем с помощью бифа is_process_alive/1. Как видно, он тоже рухнул вслед за своим слинкованным товарищем.

Теперь добавим всего одну строку — после функции вызова spawn_link/1.

process_flag(trap_exit, true), 

Это должно сделать актор raz системным. Проверим:

1> spawn_link(razdva, raz, []).
<0.86.0>
Got: {'EXIT',<0.87.0>,
             {badarith,[{math,sqrt,
                              [-13],
                              [{error_info,#{module => erl_stdlib_errors}}]},
                        {razdva,'-raz/0-fun-0-',0,
                                [{file,"razdva.erl"},{line,5}]}]}}
=ERROR REPORT==== 25-Dec-2024::15:12:14.294268 ===
Error in process <0.87.0> with exit value:
{badarith,[{math,sqrt,[-13],[{error_info,#{module => erl_stdlib_errors}}]},
           {razdva,'-raz/0-fun-0-',0,[{file,"razdva.erl"},{line,5}]}]}

2> is_process_alive(<0.86.0>).
true
3> <0.86.0> ! hello.
Got: hello
hello

Ситуация изменилась. Во-первых, мы видим, что наш системный актор обработал сообщение об ошибке:

Got: {'EXIT',<0.87.0>,

В этом сообщении сначала идёт атом ‘EXIT’, потом пид рухнувшего актора, потом собственно ошибка. Во-вторых, наш системный актор продолжил работу. Об этом свидетельствует как результат вызова is_process_alive(<0.86.0>), так и то, что актор откликается на наши сообщения.


Copyright © 2025 Алексей Карманов