ВСТУП
Модуль n2o_pi призначений для створення та відстеження контрольованих процесів у всіх додатках, використовуючи будь-які ETS таблиці. Будь-який контрольований процес у N2O створюється за допомогою n2o_pi, в тому числі: кільцеві віртуальні вузли, таймери, авторизація, процеси веб-сторінок, тестові процеси та інші сервіси. Циклічний процес всередині протокольного обробника info/2 створює нові асинхронні процеси proc/2 у випадку трудоємких операцій, тому що обробник протоколу є критичним місцем, і його слід обробляти якомога швидше.
CALLBACK
proc(term(),#pi{}) -> #ok{} | #reply{}.
proc/2 — це колбек, який буде викликано при кожному виклику gen_server'а: handle_call, handle_cast і handle_info, його init та terminate. Колбек повертає #ok як початковий стан процесу (який також є #pi{}), або його відповідь на gen_server:call/2 з новим станом, включеним в #reply.
ПРИКЛАД
Приклад буквальної реалізації таймера N2O, який позначає недійсними відповідні записи в кеш-таблиці, яка використовується для змінних сесії.
proc(init,#pi{}=Async) ->
{ok,Async#pi{state=timer(ping())}};
proc({timer,ping},#pi{state=Timer}=Async) ->
erlang:cancel_timer(Timer),
io:format("n2o Timer: ~p\r~n",[ping]),
n2o:invalidate_cache(caching),
{reply,ok,Async#pi{state=timer_restart(ping())}}.
timer(Diff) ->
{X,Y,Z} = Diff,
erlang:send_after(1000*(Z+60*Y+60*60*X),self(),{timer,ping}).
ping() ->
application:get_env(n2o,timer,{0,1,0}).
> n2o_pi:start(#pi{ module=n2o,
table=caching,
sup=n2o,
state=[],
name="timer"}).
Головне призначення n2o_pi — створювати такі процеси з однієї функції proc/2, та відстежувати pid в ETS таблиці, які визначаються під час ініціалізації процесу #pi{}.
1> supervisor:which_children(n2o).
[{{ring,4},<0.1661.0>,worker,[n2o_mqtt]},
{{ring,3},<0.1655.0>,worker,[n2o_mqtt]},
{{ring,2},<0.1653.0>,worker,[n2o_mqtt]},
{{ring,1},<0.1651.0v,worker,[n2o_mqtt]},
{{caching,"timer"},<0.1604.0>,worker,[n2o]}]
2> ets:tab2list(ring).
[{{ring,4},infinity,<0.1661.0>},
{{ring,1},infinity,<0.1651.0>},
{{ring,2},infinity,<0.1653.0>},
{{ring,3},infinity,<0.1655.0>}]
3> ets:tab2list(caching).
[{{caching,"timer"},infinity,<0.1604.0>}]
4> n2o_pi:send(caching,"timer",{timer,ping}).
n2o Timer: ping
ok
5> n2o_pi:pid(caching,"timer").
<0.1604.0>
Записи (Records)
Кожен процес керується його протоколом, який насправді є сукупністю повідомлень протоколу. Хоча n2o_pi загалом не обмежує повідомлення протоколу, однак він визначає тип стану процесу, запис #pi{}.
#ok { code = [] :: [] | #pi{} }.
#error { code = [] :: [] | term() }.
#reply { data = [] :: [] | term() ,
code = [] :: [] | #pi{} }.
По замовчуванню, в N2O кожне поле повідомлення протоколу повинно бути [].
-record(pi, { name :: atom(),
table :: ets:tid(),
sup :: atom(),
module :: atom(),
state :: term() }).
- name — ім'я процесу, ключ у контрольованому ланцюжку.
- module — назва модуля, в якому розміщено proc/2.
- table — назва ETS таблиці, де зберігається кеш pids.
- sup — додаток, в якому буде створено контрольовані процеси.
- state — стан запущеного контрольованого процесу.
API
start(#pi{}) -> {pid(),term()} | #error{}.
Запускає функцію proc/2 всередині контрольованого процесу.
stop(Class,Name) -> #pi{} | #error{}.
Зупиняє спостереження за процесом та вбиває цей процес.
restart(Class,Name) -> {pid(),term()} | #error{} | #pi{}.
Пробує завершити процес. У разу успіху запускає новий, інакше повертає помилку.
send(Class,Name,term()) -> term().
Надсилає повідомлення, отримане з таблиці Class з ключем Name, gen_call на обробку. Повертає відповідь gen_server:call.
pid(Class,Name) -> pid().
Повертає pid, який зберігався під час ініціалізації процесу в таблиці Class з ключем Name.
1> n2o_pi:pid(caching,"timer")
! {timer,ping}.
n2o Timer: ping
{timer,ping}
2> n2o_pi:send(caching,"timer",
{timer,ping}).
n2o Timer: ping
ok
3> gen_server:call(
n2o_pi:pid(caching,"timer"),
{timer,ping}).
n2o Timer: ping
ok
Цей модуль може бути пов'язаним з: n2o, n2o_proto, n2o_mqtt.