Storage of control children PID

I am starting Erlang and trying to implement my first Erlang application. This is a network monitor tool that must ping a specified host. In fact, sending ICMP is not the goal; I'm more interested in the structure of the application. I currently have monitor_app, monitor_sup (root sup), pinger_sup and pinger (working). This is pinger_sup:

-module(pinger_sup). -behaviour(supervisor). -export([start_link/0, start_child/1, stop_child/1]). -export([init/1]). start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). start_child(Ip) -> {ok, Pid} = supervisor:start_child(?MODULE, Ip), put(Pid, Ip), {ok, Pid}. stop_child(Ip) -> Children = get_keys(Ip), lists:foreach(fun(Pid) -> pinger:stop(Pid) end, Children). init(_Args) -> Pinger = {pinger, {pinger, start_link, []}, transient, 2000, worker, [pinger]}, Children = [Pinger], RestartStrategy = {simple_one_for_one, 4, 3600}, {ok, {RestartStrategy, Children}}. 

And pinger:

 -module(pinger). -behaviour(gen_server). -export([start_link/1, stop/1, stop_ping/1, ping/1, ping/2]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -define(PING_INTERVAL, 5000). start_link(Ip) -> gen_server:start_link(?MODULE, Ip, []). stop(Pid) -> gen_server:cast(Pid, stop). stop_ping(Ip) -> pinger_sup:stop_child(Ip). ping(Ip) -> pinger_sup:start_child(Ip). ping(_Ip, 0) -> ok; ping(Ip, NProc) -> ping(Ip), ping(Ip, NProc - 1). init(Ip) -> erlang:send_after(1000, self(), do_ping), {ok, Ip}. handle_call(_Request, _From, State) -> {noreply, State}. handle_cast(stop, State) -> io:format("~p is stopping~n", [State]), {stop, normal, State}. handle_info(do_ping, State) -> io:format("pinging ~p~n", [State]), erlang:send_after(?PING_INTERVAL, self(), do_ping), {noreply, State}; handle_info(Info, State) -> io:format("Unknown message: ~p~n", [Info]), {noreply, State}. terminate(_Reason, State) -> io:format("~p was terminated~n", [State]), ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. 

It has no comments, but I think it is very simple and familiar to any Erlang developer. I have few questions about this code:

1) Is erlang: send_after * in init a good solution? What is the best practice if I need a process to start working, was it spawned without running its functions from the outside?

2) I am currently running ping using pinger: ping ("127.0.0.1"). command. the pinger module will ask pinger_sup to start the child process. After the process has been started, I want to stop it. What is the preferred way to do this? Should I cancel it, or should I send him a stop command? How to store the process PID? I am currently using a process dictionary, but after implementing it, I realized that the dictionary does not actually belong to sup (this is a shell dictionary or any other calling stop_child call). In case I use ETS and sup was terminated, these dead PID processes will remain in ETS forever, what will cause a memory leak?

I appreciate any answers and comments on the code.

Thanks!

+4
source share
2 answers

1) Is erlang: send_after in init a good solution?

No.

What is the best practice if I need a process to start working, was it spawned without running its functions from the outside?

See here . Put a timeout of 0, and then do:

 handle_info(timeout, State) -> whatever_you_wish_to_do_as soon_as_server_starts, {noreply, State}. 

A zero point timeout means that the server will send itself a β€œtimeout” as soon as it finishes init, before processing any other call / listing.

Also see timer module . Instead of recrsively calling send_after on handle_info (do_ping, State), just start the timer and tell it to send you "do_ping" each? PING_INTERVAL

2) I am currently running ping using pinger: ping ("127.0.0.1"). command. the pinger module will ask pinger_sup to start the child process. After the process has been started, I want to stop it. What is the preferred way to do this? Should I stop him, or should I send him a stop command?

You must send him a stop command. Why kill gen_server with a supervisor if gen_server can do it yourself ?:-)

How to save the process PID? I am currently using a process dictionary, but after implementing it, I realized that the dictionary does not actually belong to sup (this is a shell dictionary or any other calling stop_child call). In case I use ETS and sup was terminated, these dead PID processes will remain in ETS forever, what will cause a memory leak?

ETS tables are destroyed as soon as the owner process ends. Thus, there is no memory leak.

But keeping the PID the way you do it is not an "erlang path". Instead, I suggest creating a supervisor tree. Instead of putting all the pinger workers under pinger_sup and then remembering which of the workers is pinning IP, I suggest that pinger_sup start a supervisor that processes this IP address. And then this leader begins the necessary number of workers.

Now that you want to stop pinging any IP address, you just kill the supervisor for that IP address and it will automatically kill your children.

And how do you know which supervisor is dealing with which IP address? Well, put the IP in the name of the supervisor :-) When spawning a supervisor that deals with IP, do something like this:

 -module(pinger_ip_sup). start_link(Ip) -> supervisor:start_link({global, {?MODULE, Ip}}, ?MODULE, []). 

Then, when you want to stop pinging Ip, you just kill the supervisor named {global, {pinger_ip_sup, Ip}}, and he will kill his children :-)

edit regarding comments:

If you want to handle an error that creates timeouts, you can reserve a state variable that tells you whether this is a timeout created by init or a timeout created with an error. For instance:

 -record(pinger_state, {ip, initialized}). init(Ip) -> State = #pinger_state{ip = Ip, initialized = false}. {ok, State, 0}. handle_info(timeout, State#pinger_state{initialized = false}) -> whatever_you_wish_to_do_as soon_as_server_starts, New_state = State#pinger_state{initialized = true}. {noreply, New_state}. handle_info(timeout, State#pinger_state{initialized = true}) -> error_handling, {noreply, State}. 

This way you can use this mechanism and handle timeout errors. But, the real question here is: do you expect a timeout error in general?

As for the timer: yes, the timer has some overhead if you plan to do DDOS attacks or something like that: -D If you do not plan to create and cancel timers such as crazy, it’s much more elegant to use the timer module, This is the design choice you must make: do you need a clean and elegant code, or a code that can stand when all the rest breaks. I doubt you need the latter. But, you know better.

+6
source

mybe, what do you need for Erlang's "Store Child PID of Child Elements": register (atom, PID)

+1
source

Source: https://habr.com/ru/post/1381177/


All Articles