I have a process in erlang that is supposed to do something immediately after spawn, then send the result back to the parent when it is finished. How do I figure out the PID of the process that spawned it?
You should pass self() to the child as one of the arguments to the entry function.
spawn_link(?MODULE, child, [self()]).
#Eridius' answer is the preferred way to do it. Requiring a process to register a name may have unintended side-effects such as increasing the visibility of the process not to mention the hassle of coming up with unique names when you have lots of processes.
The best way is definitely to pass it as an argument to the function called to start the child process. If you are spawning funs, which generally is a Good Thing to do, be careful of doing:
spawn_link(fun () -> child(self()) end)
which will NOT do as you intended. (Hint: when is self() called)
Generally you should avoid registering a process, i.e. giving it a global name, unless you really want it to be globally known. Spawning a fun means that you don't have to export the spawned function as you should generally avoid exporting functions that aren't meant to be called from other modules.
You can use the BIF register to give the spawning / parent process a name (an atom) then refer back to the registered name from other processes.
FUNC() ->
%% Do something
%% Then send message to parent
parent ! MESSAGE.
...
register(parent, self()),
spawn(MODULE, FUNC, [ARGS]).
See Getting Started With Erlang §3.3 and The Erlang Reference Manual §10.3.
Related
I have a gen_server process that registers a global name like this:
global:register_name(<<"CLIENT_", NAME/binary>>, self()),
Another process is trying to send this process a message using gen_server:call like this:
gen_server:call({global, <<"CLIENT_", NAME/binary>>}, {msg, DATA}),
If the second call happens before the first process registers the global name, it dies with:
exit with reason {noproc,{gen_server,call,[{global,<<"CLIENT_122">>},{msg, <<"TEST">>}]}}
What is the correct way to make a call only if the global name is register, and do something else if it is not?
Three things:
How to guard this call (mechanics).
Why you generally shouldn't want to guard the call (robust architecture).
Where you are putting your interface to this function (code structure).
Mechanics
You can check whether a name is registered with the global registry before making the call like this:
-spec send_message(Name, Message) -> Result
when Name :: term(),
Message :: term(),
Result :: {ok, term()}
| {error, no_proc}.
send_message(Name, Message) ->
case global:whereis_name(Name) of
undefined ->
{error, no_proc};
PID ->
Value = gen_server:call(PID, Message),
{ok, Value}
end.
Because there will be a few nanoseconds between the return value of global:whereis_name/1 being checked and the actual call via gen_server:call/2,3, however, so you still don't know if you actually just sent a call to a dead process, but at least you sent it to a PID that won't crash the program right away.
Another way to do it would be with a try ... catch construct, but that is a very tricky habit to get into.
Robust Architecture
All that stuff above, keep it in the back of your mind, but in the front of your mind you should want to crash if this name is unregistered. Your registered process is supposed to be alive so why are you being so paranoid?!? If thing are bad you want to know they are bad in a catastrophic way and let everything related to that crash and burn straight away. Don't try to recover on your own in an unknown state, that is what supervisors are for. Let your system be restarted in a known state and give it another go. If this is a user-directed action (some user of the system, or a web page request or whatever) they will try again because they are monkeys that try things more than once. If it is an automated request (the user is a computer or robot, for example) it can retry again or not, but leave that decision up to it in the common case -- but give it some indication of failure (an error message, a closed socket, etc.).
As long as the process you are calling registers its name during its init/1 call (before it has returned its own PID to its supervisor), and this is always happening before the calling process is alive or aware of the process to be called then you shouldn't have any trouble with this. If it has crashed for some reason, then you have more fundamental problems with your program and catching the caller's crash isn't going to help you. This is a basic idea in robustness engineering.
Structure your system so that the callee is guarantee to be alive and registered before the call can occur, and if it has died you should want the caller to die also. (Yes, I'm beating a dead horse, but this is important.)
Code Structure
Most of the time you don't want to have a module that defines a process, let's say foo.erl that defines a process we will name {global, "foo"}, have a naked call to gen_server:call/2,3 or gen_server:cast/2 that is intended for a separate process defined in another module (let's say bar.erl that defines a process we will name {global, "bar"}). What we would want is that bar.erl has an interface function that it exports, and that this function is where the gen_server:call/2 but happens.
That way any special work that applies to this call (which any other calling module may also require) exists in a single spot, and you can name the interface to the process "bar" in a way that conveys some meaning aside from the message being passed to it.
For example, if the process defined by bar.erl is a connection counter (maybe we are writing a game server and we're counting connections) we might have bar.erl be in charge of maintaining the counter. So processes send a cast (asynch message) to bar any time a new user connects. Instead of having every different process that might need to do this define some complex name checking and then naked message sending, instead consider having a function exported from bar.erl that hides that mess and is named something meaningful, like bar:notify_connect(). Just calling this in your other code is much easier to understand, and you can choose how you should be dealing with this "what if bar doesn't exist?" situation right there, in one spot.
On that note, you might want to take a look at the basic Erlang "service manager -> worker" pattern. Named processes are not overwhelmingly needed in many cases.
I am having a hard time wrapping my head around the correct way to make calls against a gen_server instance dynamically created by a supervisor with a simple_one_for_one child strategy. I am attempting to create data access controls as gen_servers. Each entity will have its own supervisor, and that supervisor will create gen_server instances as needed to actually perform CRUD operations on the database. I understand the process for defining the child processes, as well as the process for creating them as needed.
Initially, my plan was to abstract the child creation process into custom functions in the gen_server module that created a child, fired off the requested operation (e.g. find, store, delete) on that child using gen_server:call(), and then returning the operation results back to the calling process. Unless I am mistaken, though, that will block any other processes attempting to use those functions until the call returns. That is definitely not what I have in mind.
I may be stuck in OO mode (my background is Java), but it seems like there should be a clean way of allowing a function in one module to obtain a reference to a child process and then make calls against that process without leaking the internals of that child. In other words, I do not want to have to call the create_child() method on an entity supervisor and then have my application code make gen_server:calls against that child PID (i.e. gen_sever:call(Pid, {find_by_id, Id})). I would instead like to be able to call a function more like Child:find_by_id(Id).
A full answer is highly dependent on your application — for example, one gen_server might suffice, or you might really need a pool of database connections instead. But one thing you should be aware of is that a gen_server can return from a handle_call callback before it actually has a reply ready for the client by returning {noreply, NewState} and then later, once it has a client reply ready, calling gen_server:reply/2 to send it back to the client. This allows the gen_server to service calls from other clients without blocking on the first call. Note though that this requires that the gen_server has a way of sending a request into the database without having to block waiting for a reply; this is often achieved by having the database send a reply that arrives in the gen_server:handle_info/2 callback, passing enough info back that the gen_server can associate the database reply with the correct client request. Note also that gen_server:call/2,3 has a default timeout of 5 seconds, so you'll need to deal with that if you expect the duration of database calls to exceed the default.
when you create, modify or delete a record, you don't need to wait for an answer. You can use a gen_server:cast for this, but you don't need a gen_server for this, as I said in my first comment, a simple call to an interface function executed in the client process will save time.
If you want to read, 2 cases:
you can do something else while waiting the answer, then a gen_server call is ok, but a simple spawned process waiting for the answer and sending it back to the client will provide the same service.
you cannot do anything before getting the answer, then there is no blocking issue, and I think that it is really preferable to use as less code as possible so again a simple function call will be enough.
gen_server is meant to be persistent and react to messages. I don't see in your example the need to be persistent.
-module(access).
-export([add/2,get/1]).
-record(foo, {bar, baz}).
add(A,B) ->
F = fun() ->
mnesia:write(#foo{bar=A,baz=B})
end,
spawn(mnesia,activity,[transaction, F]). %% the function return immediately,
%% but you will not know if the transaction failed
get(Bar) ->
F = fun() ->
case mnesia:read({foo, Bar}) of
[#foo{baz=Baz}] -> Baz;
[] -> undefined
end
end,
Pid = self(),
Ref = make_ref(),
Get = fun() ->
R = mnesia:activity(transaction, F),
Pid ! {Ref,baz,R}
end,
spawn(Get),
Ref. %% the function return immediately a ref, and will send later the message {Ref,baz,Baz}.
If the problem you see is that you are leaking that the internal implementation of your db-process is a gen_server, you could implement the api such that it takes the pid as argument as well.
-module(user).
-behaviour(gen_server).
-export([find_by_id/2]).
find_by_id(Pid, Id) ->
gen_server:call(Pid, {find_by_id, Id}).
%% Lots of code omitted
handle_call({find_by_id, Id}, From, State) ->
ok.
%% Lots more code omitted.
This way you don't tell clients that the implementation is in fact a gen_server (although someone could use gen_server:call as well).
I have a MAIN process that spawn an implementation of a gen_fsm behavior, but this MAIN process is not an implementation of supervisor behavior, its just another module.
Let say the implementation of gen_fsm is called GAME_ROOM.
My case is like this:
When ever there are 3 peoples ready, the MAIN process will spawn a new GAME_ROOM.
I use gen_fsm:start_link function to initiate a new GAME_ROOM, so if the GAME_ROOM exit by error, my MAIN process could spawn a new one, to replace the downed process.
I managed to make my MAIN process detect the EXIT event of all downed GAME_ROOM
The problem is: I need to restore all downed GAME_ROOM states at the new one.
My question is: How can I use gen_fsm's terminate function to pass the latest states of the gen_fsm to my MAIN process, so when I respawn a new GAME_ROOM, I can pass that states?
One simple way would be for GAME_ROOM terminate/3 to send a message with the necessary state information to MAIN. For this to work the GAME_ROOM must know the pid of MAIN (easy) and you have to be certain that terminate/3 is really called.
Read about process_flag ({trap_exit, true}) and handle info 'EXIT'.
First of all, I would really suggest you to look at using supervisors in your implementation, to avoid re-inventing the wheel.
A possibility could be to create an ETS table in your MAIN, so you can store data from within your gen_fsms which can survive process crashes.
My belief is that if GAME_ROOM exits because of an error, there is nothing to save (how do you know your state is valid, otherwise you would trap the error inside GAME_ROOM).
One of the things that attracted me to Erlang in the first place is the Actor model; the idea that different processes run concurrently and interact via asynchronous messaging.
I'm just starting to get my teeth into OTP and in particular looking at gen_server. All the examples I've seen - and granted they are tutorial type examples - use handle_call() rather than handle_cast() to implement module behaviour.
I find that a little confusing. As far as I can tell, handle_call is a synchronous operation: the caller is blocked until the callee completes and returns. Which seems to run counter to the async message passing philosophy.
I'm about to start a new OTP application. This seems like a fundamental architectural decision so I want to be sure I understand before embarking.
My questions are:
In real practice do people tend to use handle_call rather than handle_cast?
If so, what's the scalability impact when multiple clients can call the same process/module?
Depends on your situation.
If you want to get a result, handle_call is really common. If you're not interested in the result of the call, use handle_cast. When handle_call is used, the caller will block, yes. This is most of time okay. Let's take a look at an example.
If you have a web server, that returns contents of files to clients, you'll be able to handle multiple clients. Each client have to wait for the contents of files to be read, so using handle_call in such a scenario would be perfectly fine (stupid example aside).
When you really need the behavior of sending a request, doing some other processing and then getting the reply later, typically two calls are used (for example, one cast and the one call to get the result) or normal message passing. But this is a fairly rare case.
Using handle_call will block the process for the duration of the call. This will lead to clients queuing up to get their replies and thus the whole thing will run in sequence.
If you want parallel code, you have to write parallel code. The only way to do that is to run multiple processes.
So, to summarize:
Using handle_call will block the caller and occupy the process called for the duration of the call.
If you want parallel activities to go on, you have to parallelize. The only way to do that is by starting more processes, and suddenly call vs cast is not such a big issue any more (in fact, it's more comfortable with call).
Adam's answer is great, but I have one point to add
Using handle_call will block the process for the duration of the call.
This is always true for the client who made the handle_call call. This took me a while to wrap my head around but this doesn't necessarily mean the gen_server also has to block when answering the handle_call.
In my case, I encountered this when I created a database handling gen_server and deliberately wrote a query that executed SELECT pg_sleep(10), which is PostgreSQL-speak for "sleep for 10 seconds", and was my way of testing for very expensive queries. My challenge: I don't want the database gen_server to sit there waiting for the database to finish!
My solution was to use gen_server:reply/2:
This function can be used by a gen_server to explicitly send a reply to a client that called call/2,3 or multi_call/2,3,4, when the reply cannot be defined in the return value of Module:handle_call/3.
In code:
-module(database_server).
-behaviour(gen_server).
-define(DB_TIMEOUT, 30000).
<snip>
get_very_expensive_document(DocumentId) ->
gen_server:call(?MODULE, {get_very_expensive_document, DocumentId}, ?DB_TIMEOUT).
<snip>
handle_call({get_very_expensive_document, DocumentId}, From, State) ->
%% Spawn a new process to perform the query. Give it From,
%% which is the PID of the caller.
proc_lib:spawn_link(?MODULE, query_get_very_expensive_document, [From, DocumentId]),
%% This gen_server process couldn't care less about the query
%% any more! It's up to the spawned process now.
{noreply, State};
<snip>
query_get_very_expensive_document(From, DocumentId) ->
%% Reference: http://www.erlang.org/doc/man/proc_lib.html#init_ack-1
proc_lib:init_ack(ok),
Result = query(pgsql_pool, "SELECT pg_sleep(10);", []),
gen_server:reply(From, {return_query, ok, Result}).
IMO, in concurrent world handle_call is generally a bad idea. Say we have process A (gen_server) receiving some event (user pressed a button), and then casting message to process B (gen_server) requesting heavy processing of this pressed button. Process B can spawn sub-process C, which in turn cast message back to A when ready (of to B which cast message to A then). During processing time both A and B are ready to accept new requests. When A receives cast message from C (or B) it e.g. displays result to the user. Of course, it is possible that second button will be processed before first, so A should probably accumulate results in proper order. Blocking A and B through handle_call will make this system single-threaded (though will solve ordering problem)
In fact, spawning C is similar to handle_call, the difference is that C is highly specialized, process just "one message" and exits after that. B is supposed to have other functionality (e.g. limit number of workers, control timeouts), otherwise C could be spawned from A.
Edit: C is asynchronous also, so spawning C it is not similar to handle_call (B is not blocked).
There are two ways to go with this. One is to change to using an event management approach. The one I am using is to use cast as shown...
submit(ResourceId,Query) ->
%%
%% non blocking query submission
%%
Ref = make_ref(),
From = {self(),Ref},
gen_server:cast(ResourceId,{submit,From,Query}),
{ok,Ref}.
And the cast/submit code is...
handle_cast({submit,{Pid,Ref},Query},State) ->
Result = process_query(Query,State),
gen_server:cast(Pid,{query_result,Ref,Result});
The reference is used to track the query asynchronously.
I have a logic module that tells a supervisor to start child processes. I need to store those childrens pid in the logic modules state. But I also need to update a childs pid if the supervisor restarts it.
So I can't use the return value pid from the start_child call, since that will only give me the pid on the first start, not the restarts. Right now I make the child process call a register function (updates state with new pid) in the logic module from the childs init function. That way the logic module can update the pid in its state whenever a process is restarted. The logic module is a gen_server and I'm doing a cast when i register the child process.
Can anyone see a problem with this and are there any other more "proper" way of doing it?
One problem is that you have the ChildPid and the child might be dead by now. So sending it a message through a cast will mean the message is lost. And through a call you will crash yourself with an {'EXIT', noproc} unless you catch it out of the call. Your solution must take into account that a Pid might be long gone the instant you send a message. Usually by ignoring that the message is lost, by crashing yourself, or by remedying the problem and then go on.
There are a couple of options. This is a loose list:
Do as you do. Let the childs register themselves.
Let the logic module have a monitor on the child. That way you know if it dies.
Use Erlang Solutions gproc module: https://github.com/esl/gproc which gives you a neat interface to an ETS table keeping track of the information. Note that you can look up a pid in gproc and await its arrival if the process is just restarting.
Use supervisor:which_children to find the relevant child.
Roll your own ETS table as a variant of gproc
local names have to be atoms, but globally registered names can be any term (they are stored internally in a ETS table looking somewhat like gproc's, see the global_name_server in kernel/stdlib). Use the global structure to track the pids in question.