Erlang. Correct way to stop process - erlang

Good day, i have following setup for my little service:
-module(mrtask_net).
-export([start/0, stop/0, listen/1]).
-define(SERVER, mrtask_net).
start() ->
Pid = spawn_link(fun() -> ?MODULE:listen(4488) end),
register(?SERVER, Pid),
Pid.
stop() ->
exit(?SERVER, ok).
....
And here is the repl excerpt:
(emacs#rover)83> mrtask_net:start().
<0.445.0>
(emacs#rover)84> mrtask_net:stop().
** exception error: bad argument
in function exit/2
called as exit(mrtask_net,ok)
in call from mrtask_net:stop/0
(emacs#rover)85>
As you see, stopping process produces error, process is stopping though.
What does this error mean and how to make thing clean ?

Not being an Erlang programmer and just from the documentation of exit (here), I'd say, that exit requires a process id as first argument whereas you are passing an atom (?SERVER) to it.
Try
exit(whereis(?SERVER), ok).
instead (whereis returns the process id associated with a name, see here)

You need to change the call to exit/2 as #MartinStettner has pointed out. The reason the process stops anyway is that you have started it with spawn_link. Your process is then linked to the shell process. When you called mrtask_net:stop() the error caused the shell process to crash which then caused your process to crash as they were linked. A new shell process is then automatically started so you can keep working with the shell. You generally do want to start your servers with spawn_link but it can cause confusion when your are testing them from the shell and they just "happen" to die.

I would suggest you to stick with OTP. It really gives you tons of advantages (I hardly can immagine the case where OTP doesn't benefit).
So, if you want to stop process in OTP you should do something like this for gen_server:
% process1.erl
% In case you get cast message {stopme, Message}
handle_cast({stopme, Message}, State) ->
% you will stop
{stop, normal, State}
handle_cast(Msg, State) ->
% do your stuff here with msg
{noreply, State}.
% process2.erl
% Here the code to stop process1
gen_server:cast(Pid, {stopme, "It's time to stop!"}),
More about it you can find here: http://www.erlang.org/doc/man/gen_server.html

Related

Link two process in Erlang?

To exchange data,it becomes important to link the process first.The following code does the job of linking two processes.
start_link(Name) ->
gen_fsm:start_link(?MODULE, [Name], []).
My Question : which are the two processes being linked here?
In your example, the process that called start_link/1 and the process being started as (?MODULE, Name, Args).
It is a mistake to think that two processes need to be linked to exchange data. Data links the fate of the two processes. If one dies, the other dies, unless a system process is the one that starts the link (a "system process" means one that is trapping exits). This probably isn't what you want. If you are trying to avoid a deadlock or do something other than just timeout during synchronous messaging if the process you are sending a message to dies before responding, consider something like this:
ask(Proc, Request, Data, Timeout) ->
Ref = monitor(process, Proc),
Proc ! {self(), Ref, {ask, Request, Data}},
receive
{Ref, Res} ->
demonitor(Ref, [flush]),
Res;
{'DOWN', Ref, process, Proc, Reason} ->
some_cleanup_action(),
{fail, Reason}
after
Timeout ->
{fail, timeout}
end.
If you are just trying to spawn a worker that needs to give you an answer, you might want to consider using spawn_monitor instead and using its {pid(), reference()} return as the message you're listening for in response.
As I mentioned above, the process starting the link won't die if it is trapping exits, but you really want to avoid trapping exits in most cases. As a basic rule, use process_flag(trap_exit, true) as little as possible. Getting trap_exit happy everywhere will have structural effects you won't intend eventually, and its one of the few things in Erlang that is difficult to refactor away from later.
The link is bidirectional, between the process which is calling the function start_link(Name) and the new process created by gen_fsm:start_link(?MODULE, [Name], []).
A called function is executed in the context of the calling process.
A new process is created by a spawn function. You should find it in the gen_fsm:start_link/3 code.
When a link is created, if one process exit for an other reason than normal, the linked process will die also, except if it has set process_flag(trap_exit, true) in which case it will receive the message {'EXIT',FromPid,Reason} where FromPid is the Pid of the process that came to die, and Reason the reason of termination.

how to create a keep-alive process in Erlang

I'm currently reading Programming Erlang! , at the end of Chapter 13, we want to create a keep-alive process,
the example likes:
on_exit(Pid, Fun) ->
spawn(fun() ->
Ref = monitor(process, Pid),
receive
{'DOWN', Ref, process, Pid, Info} ->
Fun(Info)
end
end).
keep_alive(Name, Fun) ->
register(Name, Pid = spawn(Fun)),
on_exit(Pid, fun(_Why) -> keep_alive(Name, Fun) end).
but when between register/2 and on_exit/2 the process maybe exit, so the monitor will failed, I changed the keep_alive/2 like this:
keep_alive(Name, Fun) ->
{Pid, Ref} = spawn_monitor(Fun),
register(Name, Pid),
receive
{'DOWN', Ref, process, Pid, _Info} ->
keep_alive(Name, Fun)
end.
There also an bug, between spawn_monitor/2 and register/2, the process maybe exit. How could this come to run successfully? Thanks.
I'm not sure that you have a problem that needs solving. Monitor/2 will succeed even if your process exits after register/2. Monitor/2 will send a 'DOWN' message whose Info component will be noproc. Per the documentation:
A 'DOWN' message will be sent to the monitoring process if Item dies, if Item does not exist, or if the connection is lost to the node which Item resides on. (see http://www.erlang.org/doc/man/erlang.html#monitor-2).
So, in your original code
register assocates Name to the Pid
Pid dies
on_exit is called and monitor/2 is executed
monitor immediately sends a 'DOWN' message which is received by the function spawned by on_exit
the Fun(Info) of the received statement is executed calling keep_alive/2
I think all is good.
So why you did't want to use erlang supervisor behaviour? it's provides useful functions for creating and restarting keep-alive processes.
See here the example: http://www.erlang.org/doc/design_principles/sup_princ.html
In your second example, if process exits before registration register will fail with badarg. The easiest way to get around that would be surrounding register with try ... catch and handle error in catch.
You can even leave catch empty, because even if registration failed, the 'DOWN' message, will be sent.
On the other hand, I wouldn't do that in production system. If your worker fails so fast, it is very likely, that the problem is in its initialisation code and I would like to know, that it failed to register and stopped the system. Otherwise, it could fail and be respawned in an endless loop.

why there is not output from spawned process show using escript

please could you enlighten me why following code is not using stdout if run using escript?
main(_) ->
spawn(fun() -> io:fwrite("blah") end).
Thanks!
fwrite still writes to stdout when running in an escript, the problem here is that your program terminates before the spawned process has had a chance to run!
The escript terminates as soon as the main function terminates, depending on how the virtual machine scheduled your spawned process you may or may not get the fwrite executed.
A simple workaround for your example is to add some synchronization:
main(_) ->
MainPid=self(),
spawn(fun() -> io:fwrite("blah"), MainPid ! done end),
receive
done ->
ok
end.
This makes the main process wait with termination until the spawned process has sent a message.

Erlang error when spawning a process

I start a process as follows
start() ->
register (dist_erlang, spawn(?MODULE, loop, [])),
ok.
But get the following error when trying to run start().
Error in process <0.62.0> with exit value: {undef,[{dist_erlang,loop,[]}]}
The module is called dist_erlang.
What am I doing wrong?
Thanks
Although the question is old, I post what helped me when I was wrestling with the Erlang compiler.
This (incomplete) snippet
-export([start/0]).
start() ->
Ping = spawn(?MODULE, ping, [[]]),
...
ping(State) ->
receive
...
end.
fails with error:
=ERROR REPORT==== 2-Sep-2013::12:17:46 ===
Error in process <0.166.0> with exit value: {undef,[{pingpong,ping,[[]],[]}]}
until you export explicitly ping/1 function. So with this export:
-export([start/0, ping/1]).
it works. I think that the confusion came from some examples from Learn You Some Erlang for great good where the modules sometimes have
-compile(export_all).
which is easy to overlook
Based on your previous question, your loop function takes one parameter, not none. Erlang is looking for loop/0 but can't find it because your function is loop/1.
The third parameter to spawn/3 is a list of parameters to pass to your function, and in the case you've shown the list is empty. Try:
register (dist_erlang, spawn(?MODULE, loop, [[]]))
In this case, the third parameter is a list that contains one element (an empty list).

Query an Erlang process for its state?

A common pattern in Erlang is the recursive loop that maintains state:
loop(State) ->
receive
Msg ->
NewState = whatever(Msg),
loop(NewState)
end.
Is there any way to query the state of a running process with a bif or tracing or something? Since crash messages say "...when state was..." and show the crashed process's state, I thought this would be easy, but I was disappointed that I haven't been able to find a bif to do this.
So, then, I figured using the dbg module's tracing would do it. Unfortunately, I believe because these loops are tail call optimized, dbg will only capture the first call to the function.
Any solution?
If your process is using OTP, it is enough to do sys:get_status(Pid).
The error message you mentions is displayed by SASL. SASL is an error reporting daemon in OTP.
The state you are referring in your example code is just an argument of tail recursive function. There is no way to extract it using anything except for tracing BIFs. I guess this would be not a proper solution in production code, since tracing is intended to be used only for debug purposes.
Proper, and industry tested, solution would be make extensive use of OTP in your project. Then you can take full advantage of SASL error reporting, rb module to collect these reports, sys - to inspect the state of the running OTP-compatible process, proc_lib - to make short-lived processes OTP-compliant, etc.
It turns out there's a better answer than all of these, if you're using OTP:
sys:get_state/1
Probably it didn't exist at the time.
It looks like you're making the problem out of nothing. erlang:process_info/1 gives enough information for debugging purposes. If your REALLY need loop function arguments, why don't you give it back to caller in response to one of the special messages that you define yourself?
UPDATE:
Just to clarify terminology. The closest thing to the 'state of the process' on the language level is process dictionary, usage of which is highly discouraged. It can be queried by erlang:process_info/1 or erlang:process/2.
What you actually need is to trace process's local functions calls along with their arguments:
-module(ping).
-export([start/0, send/1, loop/1]).
start() ->
spawn(?MODULE, loop, [0]).
send(Pid) ->
Pid ! {self(), ping},
receive
pong ->
pong
end.
loop(S) ->
receive
{Pid, ping} ->
Pid ! pong,
loop(S + 1)
end.
Console:
Erlang (BEAM) emulator version 5.6.5 [source] [smp:2] [async-threads:0] [kernel-poll:false]
Eshell V5.6.5 (abort with ^G)
1> l(ping).
{module,ping}
2> erlang:trace(all, true, [call]).
23
3> erlang:trace_pattern({ping, '_', '_'}, true, [local]).
5
4> Pid = ping:start().
<0.36.0>
5> ping:send(Pid).
pong
6> flush().
Shell got {trace,<0.36.0>,call,{ping,loop,[0]}}
Shell got {trace,<0.36.0>,call,{ping,loop,[1]}}
ok
7>
{status,Pid,_,[_,_,_,_,[_,_,{data,[{_,State}]}]]} = sys:get_status(Pid).
That's what I use to get the state of a gen_server. (Tried to add it as a comment to the reply above, but couldn't get formatting right.)
As far as I know you cant get the arguments passed to a locally called function. I would love for someone to prove me wrong.
-module(loop).
-export([start/0, loop/1]).
start() ->
spawn_link(fun () -> loop([]) end).
loop(State) ->
receive
Msg ->
loop([Msg|State])
end.
If we want to trace this module you do the following in the shell.
dbg:tracer().
dbg:p(new,[c]).
dbg:tpl(loop, []).
Using this tracing setting you get to see local calls (the 'l' in tpl means that local calls will be traced as well, not only global ones).
5> Pid = loop:start().
(<0.39.0>) call loop:'-start/0-fun-0-'/0
(<0.39.0>) call loop:loop/1
<0.39.0>
6> Pid ! foo.
(<0.39.0>) call loop:loop/1
foo
As you see, just the calls are included. No arguments in sight.
My recommendation is to base correctness in debugging and testing on the messages sent rather than state kept in processes. I.e. if you send the process a bunch of messages, assert that it does the right thing, not that it has a certain set of values.
But of course, you could also sprinkle some erlang:display(State) calls in your code temporarily. Poor man's debugging.
This is a "oneliner" That can be used in the shell.
sys:get_status(list_to_pid("<0.1012.0>")).
It helps you convert a pid string into a Pid.

Resources