How to share a child manager pid with another child in Erlang / OTP

In my Erlang / OTP application, I have one_for_all ( sup ) dispatcher with several children. One of the children ( child1 with the behavior of gen_server ) should be able to send messages to the other ( child2 with the behavior of supervisor ). Of course, I can register it, but clogging the global area with redundant names does not seem like a good idea.

Thus, the only way to make this interaction possible is to provide child1 pid child2 . No sooner said than done. There is a supervisor:wich_children/1 call supervisor:wich_children/1 with the corresponding functionality. Just pass sup pid as an argument to chidl1 , calling which_children in child1:init and ... getting a dead end. sup is waiting for child1 , child1 is waiting for sup to describe the children:

 init(SupPid) -> Descriptions = supervisor:which_children(SupPid), ... . 

This can be fixed with the following kludge:

 init(SupPid) -> gen_server:cast(self(), initialize), ... . handle_cast(initialize, State) -> Descriptions = supervisor:which_children(SupPid), ... % Generating new state containing desired pid {noreply, NewState}. 

However, I was not satisfied with this decision.

Question: What is the most common way of interaction between elements of the observation tree in accordance with the principles of OTP design?

+6
source share
2 answers

Undoubtedly, you cannot ask a leader about your children before he starts them :)

Registering (locally using erlang: register ()) is actually not such a bad idea. In addition, if you are dealing with a raw pid in child1, you must manually configure monitoring for child2 pid in order to be able to respond to possible failures, etc., but, being registered, you simply request it immediately by name.

Without registering, you can defer notification of children until the supervisor is called: start_link is called:

 start_link() -> R=supervisor:start_link({local, ?SERVER}, ?MODULE, []), %% Here supervisor is started so you can notify its children R. 
+5
source

It depends on your business logic, but if you have a reason to worry about clogging the global realm, I suggest you consider the surveillance strategy that you are using.

What I saw in such cases when two peer processes should be connected in this way is that an additional controller process is created to control this association, and simple_one_for_one sup is used to create one of the two peer processes (most likely, gen_server) . This method, again, can be used when using process registration, is a problem, for example, when you have many instances of these gen_servers working with the same code.

Basically it will be to use the simple_one_for_one control to start your gen_server. What happens mostly is that when you start (simple_one_for_one sup), no child processes happen immediately, but only when you explicitly call supervisor:start_child(Sup, List) .

Then your child2 initialization logic (or even your business logic at some point) could generate gen_server via supervisor:start_child(Sup, List) and be served with child2 Pid so that they can communicate painlessly.

In the additional controller process, a dictation is stored between your gen_server, identified by some uniqueness, but eliminating the clogging of global space, since it is simply local to the controller. You can then ask your controller to distribute or release this connection anywhere in your logic.

The observation tree should look something like this:

inspection tree

You can read the code using this implementation in a tinymq project on github

If you have never used the simple_one_for_one super processor before, the specification for the child can be a little complicated, remember that you passed the child2 pid to your gen_server via a list on supervisor:start_child(Sup, List) , which is added to the Args element that you point to the child specifications.

simple_one_for_one supervisors

My two cents!

+1
source

All Articles