Home > English, Erlang > A survival guide on pg2 Erlang module

A survival guide on pg2 Erlang module


Today I will enjoy part of my holidays to introduce you a very interesting Erlang module: pg2.

This module  implements a trivial distributed process groups. Now, if you already took a look at this topic in Erlang, you should know that other modules provides “similar” functionalities for handling distributed process groups (e.g. pg and pool). I leave the analysis of these two modules to a possible future post, but I would like to emphasize what is in my humble opinion the main difference between pg2 and pg.

Giving that a process group is a group of processes that can be accessed by a common name:

  • in pg module, when messages are sent to the named group, all members of the group receive the message
  • in pg2 module, each message may be sent to one, some, or all members

You can imagine a process group as a group which is populated with one or more processes (e.g. a gen_server). The aforesaid group can be accessed by a common name. The  processes can be located on the same node or on  different nodes and messages can be sent to one, some, or all members of the group.

As a rule of thumb, in this blog I never go really deep with theory…(I’m a practical guy) so to explain more pg2 I will write and comment few lines of code. Hopefully the example will help you to understand quite well the topic!🙂

pegaso:~ pdincau$ erl
Erlang (BEAM) emulator version X.Y.Z

Eshell VX.Y.Z (abort with ^G)

1> pg2:create(test).
ok
2> pg2:which_groups().
[test]
3> pg2:join(test, self()).
ok
4> pg2:get_members(test).
[<0.31.0>]
5> a = b.
** exception error: no match of right hand side value b
6> self().
<0.38.0>
7> pg2:get_members(test).
[]
8> pg2:join(test, self()).
ok
9> pg2:get_closest_pid(test).
<0.38.0>
10> pg2:leave(test, self()).
ok
11> pg2:delete(test).
ok

First of all I used pg2:create/1 which creates a new process group given a name, in my case I used the atom ‘test’. Ok, now we have a working group, and we can check this out by calling pg2:which_groups/0.

This group for now is totally not useful, since no process has joined it yet. Let’s now add some processes using the function pg2:join/2 which takes as input the name of the group you want to join to and the pid of the process which will join (in this example I added only the shell process). I the join procedure goes in the right way you should receive an ok, but you can double check this by using pg2:get_members/1, a function that given as input the name of a group, returns the processes that joined the group and are still running. You may also want to try pg2:get_local_members/1 which does basically the same thing, but in local node.

What happens if a process exits? Should you remove manually the process from the group? No! The nice thing of pg2 is that dead processes are automatically removed from the group. As you may see at line 5 I crashed on purpose the process of the VM. After that I checked for the members of the group and voilà: no process was in the group! I have to be honest with you: in some versions of the Erlang machine, the module pg2 is not working as expected (remember this module is a beta!). When I did my first experiments with this module I didn’t know the existence of this problem, so I struggled with it since I found this webpage. I have to say also that my problem was solved simply by upgrading my Erlang environment. I have digressed a little here! Forgive me for this but I think that this information was really important!

What is left to say about pg2? Let’s say you want your process to leave a group it joined before, you can use pg2:leave/2 which works in the opposite way of pg2:join/2. Last but not least you may want to delete a group: in this case you can use pg2:delete/1 which will delete the group registered with the name given as input to the function.

Hei!!! Something is missing here!🙂 How do I interact with a process group? You may have noticed I used pg2:get:closest_pid/1 in the code above, well that function:

  • randomly chooses a local process of group if one exists
  • otherwise randomly chooses a remote process of group

After the pid is returned we can contact as we do with normal processes (e.g. the ! operator or a gen_server call).

Is there a better way to choose one among all the group members? Well, in this post I have read time ago there is a really nice solution:

get_best_pid(Group) ->
  Members = pg2:get_members(Group),
  Members1 = lists:map(fun(Pid) ->
      [{message_queue_len, Messages}] = erlang:process_info(Pid, [message_queue_len]),
                                                                 {Pid, Messages}
                       end, Members),
case lists:keysort(2, Members1) of
  [{Pid, _} | _] -> Pid;
  [] -> {error, empty_process_group}
end.

As you can see here, the best_pid is the one with the lower message_queue_len. Other solutions are feasible, so take a look at erlang:process_info/1 for details.

In one of my previous posts I created a sort of “configuration process” which after the start used message passing to furnish configuration parameters to other processes. That kind of implementation introduced few problems, one of them was a possible bottleneck: we could have had thousands of processes asking for configuration parameters, and only one process to provide them. In the next post I will show you how I implemented such code.

Note: if you are interested in process pool implementation take a look at this: http://learnyousomeerlang.com/building-applications-with-otp

Categories: English, Erlang Tags: , ,
  1. Max
    January 9, 2013 at 2:59 pm

    erlang:process_info(Pid, …) does not work for remote Pid. Only local PId is allowed.

    • pdincau
      January 9, 2013 at 3:19 pm

      I guess you mean that in the list comprehension the BIF process_info fails when we have in the group pids of processes from different nodes. Right? Actually the example above was written with a group of processes all in the same erlang node

  2. January 20, 2015 at 7:20 am

    Once you mentioned you wrote some code to implement pool service🙂 It would be more than nice to read your code, really. If all Erlang books were written in your style I would have read them all for one week…

  1. September 18, 2012 at 9:42 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: