Registering a child in the process that initiated the start_child call - erlang

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.

Related

gen_server:call on a global name that is not registered

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.

how to handle termination of gen_fsm

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).

Data persistence when worker process dies, how?

I have worker processes that needs gathered/calculated data as arguments on start up. This is then needed on re-starts as well. Where should I put the initialization code? Inside the supervisors init? Or inside the modules start_link, or init? Are there any best practices in Erlang when it comes to this?
If the gen_server component has critical state, or state which cannot be re-calculated/re-gathered, I generally avoid keeping the state in gen_server itself. I instead choose to maintain state in an external process/ets table. If you are going by this approach, make sure the ets table is either created by an externel process (which you are sure will not die), for eg., the application process -or- create the ets table in the init method of the gen_server and use the "ets:give_away/3" method to hand it off to an external process (of course, you would need to check if the table is already created in the gen_server's init method).. Else the ets table will be destroyed when the process dies..

State in OTP event manager process (not handler!)

Can an OTP event manager process (e.g. a logger) have some state of its own (e.g. logging level) and filter/transform events based on it?
I also have a need to put some state into the gen_event itself, and my best idea at the moment is to use the process dictionary (get/put). Handlers are invoked in the context of the gen_event process, so the same process dictionary will be there for all handler calls.
Yes, process dictionaries are evil, but in this case they seem less evil than alternatives (ets table, state server).
The gen_event implementation as contained in the OTP does no provide means for adding state.
You could extend the implementation to achieve this and use your implementation instead of gen_event. However I would advise against it.
The kind of state you want to add to the event manager belongs really in the event handler for several reasons:
You might want to use different levels in different handlers, e.g. only show errors on the console but write everything to the disk.
If the event level would be changed in the manager event handlers depending on getting all unfiltered events might cease to function (events have more uses than just logging). This might lead to hard to debug problems.
If you want a event manager for multiple handlers that all only get filtered events you can easily achieve this by having two managers: one for unfiltered messages and one for e.g. level filtered messages. Then install a handler to the unfiltered one, filter in the handler by level (easy) and pass on the filtered events to the other manager. All handlers that only want to get filtered messages can be registered to the second manager.
The handlers can have their own state that gets passed on every callback like:
Module:handle_event(Event, State) -> Result
Filtering might look like this (assuming e.g. {level N, Content} events):
handle_event({level, Lvl, Content}, State#state{max_level=Max}) when Lvl >= Max ->
gen_event:notify(filtered_man, Content);
The State can be changed either by special events, by gen_event:call\3,4 (preferably) or by messages handled by handle_info.
For details see Gen_Event Behaviour and gen_event(3)
When you start_link a gen_event process - thing that you should always do via a supervisor -, you can merely specify a name for the new process, if you need/want it to be registered.
As far as I can see, there's no way to initiate a state of some sort using that behaviour.
Of course, you can write your own behaviour, on the top of a gen_event or of a simple gen_server.
As an alternative, you might use a separate gen_event process for each debugging level.
Or you can just filter the messages in the handlers.

How Do You Determine The PID of the Parent of a Process

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.

Resources