After watching the Pragmatic Studio screen casts on Erlang, the last video on Supervisors mentioned that in order for a supervisor to get a notification about one of its children so it can properly restart it, the child should register with process_flag(trap_exit, true). Perhaps I just misunderstood the author (and chances are VERY high that I did misunderstand), but I thought supervisors automagically know when their children die (probably through spawn_link or something similar in the background). Is this really necessary? When should one use process_flag(trap_exit, true) in a real world case because the documentation explicitly states the following:
http://www.erlang.org/doc/man/erlang.html#process_flag-2
process_flag(trap_exit, Boolean)
When trap_exit is set to true, exit signals arriving to a process are converted to {'EXIT', From, Reason} messages, which can be received as ordinary messages. If trap_exit is set to false, the process exits if it receives an exit signal other than normal and the exit signal is propagated to its linked processes. Application processes should normally not trap exits.``
You have 3 idioms:
1/ I don't care if my child process dies:
spawn(...)
2/ I want to crash if my child process crashes:
spawn_link(...)
3/ I want to receive a message if my child process terminates (normally or not):
process_flag(trap_exit, true),
spawn_link(...)
Please see this example and try different values (inverse with 2 or 0 to provoke an exception, and using trap_exit or not):
-module(play).
-compile(export_all).
start() ->
process_flag(trap_exit, true),
spawn_link(?MODULE, inverse, [2]),
loop().
loop() ->
receive
Msg -> io:format("~p~n", [Msg])
end,
loop().
inverse(N) -> 1/N.
Supervisors use links and trap exits so they can keep track of their children and restart them when necessary. Child processes do not have to trap exits to be properly managed by their supervisors, indeed they should only trap when they specifically need to know that some process to which they are linked dies and they don't want to crash themselves.
The OTP behaviours are able to properly handle supervision if they are trapped or not trapped.
In Erlang, processes can be linked together. These links are bi-directional. Whenever a process dies, it sends an exit signal to all linked processes. Each of these processes will have the trapexit flag enabled or disabled. If the flag is disabled (default), the linked process will crash as soon as it gets the exit signal. If the flag has been enabled by a call to system_flag(trap_exit, true), the process will convert the received exit signal into an exit message and it will not crash. The exit message will be queued in its mailbox and treated as a normal message.
If you're using OTP supervisors, they take care of the trap_exit flags and details for you, so you don't have to care about it.
If you're implementing a supervision mechanism, which is probably what the screen-cast is about (haven't seen it), you will have to take care of the trap_exit thing.
Related
E.g. suppose I have a module that implements gen_server behavior, and it has
handle_call({foo, Foo}, _From, State) ->
{reply, result(Foo), State}
;
I can reach this handler by doing gen_server:call(Server, {foo, Foo}) from some other process (I guess if a gen_server tries to gen_server:call itself, it will deadlock). But gen_server:call blocks on response (or timeout). What if I don't want to block on the response?
Imaginary use-case: Suppose I have 5 of these gen_servers, and a response from any 2 of them is enough for me. What I want to do is something like this:
OnResponse -> fun(Response) ->
% blah
end,
lists:foreach(
fun(S) ->
gen_server:async_call(S, {foo, Foo}, OnResponse)
end,
Servers),
Result = wait_for_two_responses(Timeout),
lol_i_dunno()
I know that gen_server has cast, but cast has no way to provide any response, so I don't think that that's what I want in this case. Also, seems like it should not be the gen_server's concern whether caller wants to handle response synchronously (using gen_server:call) or async (does not seem to exist?).
Also, the server is allowed to provide response asynchronously by having handle_call return no_reply and later calling gen_server:reply. So why not also support handling response asynchronously on the other side? Or does that exist, but I'm just failing to find it??
gen_server:call is basically a sequence of
send a message to the server (with identifier)
wait for the response of that particular message
wrapped in a single function.
for your example you can decompose the behavior in 2 steps: a loop that uses gen_server:cast(Server,{Message,UniqueID,self()} with all servers, and then a receive loop that wait for a minimum of 2 answers of the form {UniqueID,Answer}. But you must take care to empty your mail box at some point in time. A better solution should be to delegate this to a separate process which will simply die when it has received the required number of answers:
[edit] make some correction in the code now it should work :o)
get_n_answers(Msg,ServerList,N) when N =< length(ServerList) ->
spawn(?MODULE,get_n_answers,[Msg,ServerList,N,[],self()]).
get_n_answers(_Msg,[],0,Rep,Pid) ->
Pid ! {Pid,Rep};
get_n_answers(_Msg,[],N,Rep,Pid) ->
NewRep = receive
Answ -> [Answ|Rep]
end,
get_n_answers(_Msg,[],N-1,NewRep,Pid);
get_n_answers(Msg,[H|T],N,Rep,Pid) ->
%gen_server:cast(H,{Msg,Pid}),
H ! {Msg,self()},
get_n_answers(Msg,T,N,Rep,Pid).
and you cane use it like this:
ID = get_n_answers(Msg,ServerList,2),
% insert some code here
Answer = receive
{ID,A} -> A % tagged with ID to do not catch another message in the mailbox
end
You can easily implement that by sending each call in a separate process and waiting for responses from as many as required (in essence this is what async is about, isn't? :-)
Have a look at this simple implementation of parallel call which is based on the async_call from rpc library in OTP.
This is how it works in plain English.
You need to make 5 calls so (in the parent process) you spawn 5 child Erlang processes.
Each process sends back to the parent process a tuple containing its PID and the result of the call.
The tuple can be only constructed and send back only when the desired call has been completed.
In the parent process you loop through responses in the receive loop.
You can wait for all responses or just 2 or 3 out of the started 5.
The parent process (which spawns the worker processes) will eventually receive all responses (I mean those you want to ignore). You need a way to discard them if you don't want the message queue to grow infinitely. There are two options:
The parent process itself can be a transient process, created only for the call to spawn the other 5 child processes. Once the desired amount of responses is collected it can send the response back to a caller and die. Messages send to the died process will be discarded.
The parent process can continue receiving messages after it has received the desired amount of responses and simply discard them.
gen_server do not have a concept of async calls on client side. It is not trivial how to implement in consistently because gen_server:call is a combination of monitor for server process, send request message and wait for either answer or monitor down or timeout. If you do something like what you mentioned you will need to deal with DOWN messages from server somehow ... so hypothetical async_call should return some key for yeld and also an internal monitor reference for a case you are processing DONW messages from other processes... and do not want to mix it with yeld errors.
Not that good but possible alternative is to use rpc:async_call(gen_server, call, [....])
But this approach have a limitation in calling process will be a short lived rex child, so if your gen server use caller pid somehow other than send it a reply logic will be broken.
gen_sever:call to the process itself would surely block until timeout. To understand the reason, one should be aware of the fact that gen_server framework actually combine your specific code together into one single module, and gen_server:call would be "translated" as "pid ! Msg" form.
So imagine how this block of code takes effect, the process actually stay in a loop keeping receiving messages, and when the control flow run into a handling function, the receiving process is temporarily interrupted, so if you call gen_server:call to the process itself, since it is a synchronous function, it waits for response, which however would never come in until the handing function returns so that the process can continue to receive messages, so the code is in a deadlock.
If I have a process A that makes call to a function in process B (procB:func().), and func() generates an error during execution. Process B would terminate, but what about process A? Consider the following in process A:
Case 1:
{ok, Reply} = procB:func().
Case 2:
procB:func().
Will process A terminate in both cases? Or just in case 1 because of mismatch? Please note that the two processes are not linked.
Thanks in advance!
There is no such thing as calling a function in another process, you can send a message to a process that it then may choose to call a function based on message content.
gen_servers work this way, you send a message to the gen_server, and it does a match on the message and chooses if it should invoke call/cast/info/terminate functions.
Assuming you are really talking about sending a message from A to B and B decides to exit, it's all about if process A is linked/monitoring process B.
If you monitor B, you are sent a message saying that B went down and the reason.
If you are linked to B, I believe the rule is you are killed if B died with a status other than 'normal'
A could also have set the flag trap_exit, which means that even if linked and B dies, A is sent a message that he should die and you get to interact with that message (ie: you may restart B, if you choose)
learn you some erlang has a good tutorial on how this works.
You are not able to call function in another process. That is the beauty of Erlang: all communication between processes is via message passing. People sometimes confuse modules with processes. I even wrote article about it.
For example process A:
spawns process B
sends message which is for example tuple {fun_to_call, Args, self()} (you need the self() to know, where to respond
waits for reply using receive
Process B:
immediately after start waits for message
when receives message, does some computation and sends response back
This looks like a lot of boilerplate, so this exact pattern is abstracted in gen_server
If an Erlang process proc1 is killed (exit(killed)) and another process proc2 is notified of this event because it's linked to the process proc1, is there a possibility to respawn a replacement process with the mailbox of the killed process proc1?
Not really. Processes don't share any data, so when one dies no other can access any of it's memory. Erlang would not know how long to wait to garbage-collect such mailbox.
You could simulate that with separate proxy process that just keeps track of mailbox.
Or you could try to handle little better being killed in proc1. You could use process_flag(trap_exit, true) which would allow you to receive exit(killed) message as normal message {'EXIT',FromPid,killed}. And when you receive you read you whole mailbox, and then continue exiting with all messages being part of exit reason.
It could look somewhat like this:
init(Args) ->
process_flag(trap_exit, true),
.... % continiue process innicializaiton.
loop(State) ->
receive
....
{'EXIT', _FromPid, killed} ->
exit({killed, all_messages()})
end.
all_messages() ->
all_messages([]).
all_messages(Messages) ->
receive
AnyMessage ->
all_messages( [AnyMessage|Messages])
after 0 ->
lists:reverse(Messages)
end.
And proc2 would receive all unprocessed messages, and could send them again to newly spawn process.
When I need to create a process,I will use the customary spawn bif.But there is one more bif spawn_link that is often used to do the same thing.
So basically when should one use spawn and spawn_link?
Doing spawn and then link manually is equivalent in operation to spawn_link, but it is not equivalent in time; in particular it is not atomic (as in, two independent operations, not a single, indivisible one). If you spawn a process and it dies in its initialization (whatever your start or init functions do) then it might die before the call to link completes, and the linked process will never get notified that the process died since it died before it was linked. Oops!
From Joe Armstrong's Programming Erlang Ch.13 "Why Spawning and Linking Must be an Atomic Operation":
Once upon a time Erlang had two primitives, spawn and link, and spawn_link(Mod, Func, Args) was defined like this:
spawn_link(Mod, Func, Args) ->
Pid = spawn(Mod, Func, Args),
link(Pid),
Pid.
Then an obscure bug occurred. The spawned process died before the link statement was called, so the process died but no error signal was generated. This bug took a long time to find. To fix this, spawn_link was added as an atomic operation. Even simple-looking programs can be tricky when concurrency is involved.
spawn just spawns a new process.
spawn_link spawns a new process and automatically creates a link between the calling process and the new process. So it can be implemented as:
my_spawn_link(Module, Function, Args) ->
Pid = spawn(Module, Function, Args),
link(Pid),
Pid.
This could be a very basic question but is Erlang capable of calling a method on another prcoess and wait for it to repond back with some object type without sleeping threads?
Well, if you're waiting for an answer, the calling process will have to sleep eventually… But that's no big deal.
While processes are stuck on the receive loop, other processes can work. In fact, it's not uncommon to have thousands of processes just waiting for messages. And since Erlang processes are not true OS threads, they're very lightweight so the performance loss is minimal.
In fact, the way sleep is implemented looks like:
sleep(Milliseconds) ->
receive
% Intentionally left empty
after Milliseconds -> ok
end.
Yes, it is possible to peek into the mailbox if that is what you mean. Say we have sent a message to another process and now we want to see if the other process has sent something back to us. But we don't want to block on the receive:
receive
Pattern -> Body;
Pattern2 -> Body2
after 0 ->
AfterBody
end
will try to match against the Pattern and Pattern2 in the mailbox. If none matches, it will immediately time out and go to AfterBody. This allows you to implement a non-blocking peek into the mailbox.
If the process is a gen_server the same thing can be had by playing with the internal state and the Timeout setting when a callback returns to the gen_server's control. You can set a Timeout of 0 to achieve this.
What am getting from the question is that we are talking of Synchronous Message Passing. YES ! Erlang can do this perfectly well, its the most basic way of handling concurrency in Erlang. Consider this below:
rpc(Request, To)->
MySelf = self(),
To ! {MySelf,Request},
receive
{To,Reply} -> Reply
after timer:seconds(5) -> erlang:exit({error,timedout})
end.
The code above shows that a processes sends a message to another and immediately goes into waiting (for a reply) without having to sleep. If it does not get a reply within 5 seconds, it will exit.