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!