Archive

Many times if you work with Erlang and follow the OTP design principles in your implementation, you may end up having one or more supervisors spawning a set of processes that can be either other supervisors or workers.

Most likely the child processes implementing the workers will be based on gen_server behaviour and whether you’re working on your small side project or in some big company project they will need some sort of initialization during the start-up phase: in fact creating an ets or mnesia table, reading a configuration file or accepting connections on a socket are pretty common operations that you want to be executed before the worker handles other messages and executes the operations connected to such messages.

According to the relative documentation, the gen_server process calls Module:init/1 to initialize and therefore the first strategy you may think to employ consists in doing the operations listed above within this function. What I mean here is something like:

This kind of approach is pretty common when the operations we want to take during initialization are cheap in terms of time, but what happens if the initialisation is expected to take a long time?

Suppose you have a supervisor that spawns many children and each child has some long time taking configuration. The supervisor will probably call the function start_link/3,4 of each child in sequence and will not be able to return until Module:init/1 of the child it is starting has returned. This means that the supervisor won’t be able to start the next children on the fly and this will somehow slow down the whole supervisor startup phase.

How can we solve this issue? Well, there are a couple of different ways to do it, but all of them are based on splitting the gen_server initialisation into two phases, a first phase implemented in the init/1 function during which we trigger some internal message for a future configuration and that returns immediately to the supervisor and a second phase in which the configuration actually takes place. In such a way we can free the supervisor startup from the time burden of all the children configurations.

Let’s see with some code what are the most common ways to achieve this results. My favourite technique consists into triggering the future configuration using a gen_server cast inside the init/1 function as follows:

As you can see within the init/1 function we trigger a cast message to our process and immediately return. At this point we just need to handle the cast in the function handle_cast/2 and perform the needed configuration. This can be done in this way:

As you can see the logic is pretty much the same here so I won’t go into further details.

The last way to achieve our result can be implemented by taking advantage of a timeout message. In practice in the init/1 function, instead of returning the tuple {ok, #state{}} we return the tuple {ok, #state{}, Timeout}. By including the value Timeout in the last tuple we specify that a ‘timeout’ atom will be sent to our gen_server unless a request or a message is received within Timeout milliseconds.

The ‘timeout’ atom should be handled by the handle_info/2 callback function. By setting the value of Timeout to 0 and adapting handle_info we can implement once again in an easy way our “two phases” configuration. Let’s see how this can be obtained:

Personally I don’t like the last approach because the atom ‘timeout’ is not so meaningful and it can lead to some misunderstanding. By the way the real problem here is that this approach is implemented taking advantage of an internal timer that should be evaluted: we can’t be sure that the message will be sent immediately, we just know that the message will be sent after at least 0 milliseconds.

Some reader here may say that this “two phases” approach is risky, because no one assures us that the configuration message will be the first message handled either in handl_cast/2 or handle_info/2. Actually this is not completely true.

We can’t be sure 100% that a message sent in init/1 using either a cast of the operator ! will be the first one in the process queue of our gen_server, but considering that start_link/3,4 is synchronous there are really few chances for another process to send a message to our gen_server before we send the configuration message.

Final consideration: there is a more elegant way to achieve the same result that consists in the combination of the functions start_link/3 and init_ack/1 of the module proc_lib. For those of you interested in the topic I suggest the user guide of ranch.

The game my flatmates and I play the most is for sureMonster Hunter Tri for WII. In this game you control an hunter which goes around, kills/captures monsters and so on. In the world of Monster Hunter is quite common to find (as in any other good game) some sort of “gather spot”, which are nothing more than places where you can find herbs to be picked up or rocks to be mined. A couple of days ago, while my friends where playing I started emacs and I started implementing a super simple gather spot.

I decided that my gather spot should respect these rules:

gather spot should be a non registered process

gather spot should be a gen_server process

gather spot can handle messages from players asking for a drop (if you don’t know what a drop is check outthis)

gather spot should have different drops according to its type (e.g. rock/herb)

gather spot should have a random number of drops

gather spot should have different probabilities of drop (a friend of mine lost his mind trying to get “Eternal strife” rust shards)

gather spot should stop when it has nothing more to drop

In this post I will neither tell you how I managed the location of the gather spot in the XY-plane, nor how I configured a supervision tree for them; I want only to show you how simple is to implement something working in Erlang. You may notice that in my code I didn’t register with a name the process, this is due to the fact that I may have a huge number of this kind of process in a single Erlang node. Here follow resource.erl and helper.hrl…I will not give you explanation about these two files since they are quite simple.

As you can see, the code above is fairly simple and respect all the rules I introduced above. You may notice that resource type, drops number and actual drop are random. The important thing here is that the gen_server which represents the resource will exit in normal way when no more drops are present in its state. Let’s see helper.hrl, which will give you some better insight:

Now, some may argue that this code is far from perfect…well I agree. In fact this is just a starting point…a lot of stuff can be improved, therefore why don’t you start from this code and do something on you own? How can you improve this code? Here some ideas:

how would you place in a random way a resource spot in a given x-y or x-y-x point?

A supervisor is an OTP behaviour (a process design pattern) made available in a set of library modules that come with the normal Erlang distribution. In practice a supervisor is a piece of code, done by expert developers, which simplyfies our life!
Basically OTP provides two different kinds of processes: workers (e.g. gen_servers or gen_fsm) that as you can easily understand do the actual job and supervisors which monitor workers’s (or other supervisors’s) statuses.

The supervisor is started by the function start_link/0, which call the init/1 function.

As you can see we declared a variable named Child which represents the specification of a child for which the supervisor is responsible.

The variable is in the form: {Id, StartFunc, Restart, Shutdown, Type, Modules}

Id : is the name used to identify the child specification internally by the supervisor

StartFunc : represents the function used to start the child process. It is a module-function-arguments tuple used as apply(M, F, A)

Restart : defines when a terminated child process should be restarted. It can be one between:

permanent : in this case child process is always restarted

transient : in this case child process is restarted only if it terminates abnormally, i.e. with another exit reason than normal

temporary : in this case child process is never restarted

Shutdown : defines how a child process should be terminated

brutal_kill : in this case child process is unconditionally terminated using exit(Child, kill)

integer value : in this case the supervisor tells the child process to terminate by calling exit(Child, shutdown) and then waits for an exit signal back. If no exit signal is received within the specified time, the child process is unconditionally terminated using exit(Child, kill)

infinity : in this case child process is another supervisor, shutdown should be set to infinity to give the subtree enough time to shutdown

Type : it specifies if the child process is a supervisor or a worker (can be supervisor/worker)

Modules : this should be a list with one element [Module], where Module is the name of the callback module, if the child process is a supervisor, gen_server or gen_fsm. If the child process is a gen_event, Modules should be dynamic

The last tuple is in the form: {ok, {{RestartStrategy, MaxR, MaxT}, [Child]}}

RestartStrategy : indicates how to handle process restart. Can be one of the following:

one_for_one: if the corresponding child process terminates, only that process is restarted

one_for_all :if the child process terminates, all other child processes are terminated and then all child processes, including the terminated one, are restarted

rest_for_one : if the child process terminates, the ‘rest’ of the child processes (i.e. the child processes after the terminated process in start order ) are terminated. Then the terminated child process and the rest of the child processes are restarted

MaxR and MaxT are related: if more than MaxR number of restarts occur in the last MaxT seconds, then the supervisor terminates all the child processes and then itself. When the supervisor terminates, then the next higher level supervisor takes some action. It either restarts the terminated supervisor, or terminates itself.

As you can see the only element inside the list is Child that contains the child specifications we set before; obviously you can add to this list more than one child specification.

Let’s test our supervisor. The first thing that I will do is coding a simple gen_server that prints a message anytime it is started:

As you can see as we start the supervisor, the child is started as well with the pid <0.36.0>.

After that we kill that child process using the Erlang BIF exit/2; at that point the supervisor restarts the child and a following whereis/1 command shows that the process has been restarted with a new pid <0.39.0>.

In the previous post, I have told you how to make a counter server in C and then call its functionalities through RPC calls.

In Erlang it is defined a module called rpc. It provides services which are similar to remote procedure calls. It also contains broadcast facilities and parallel evaluators. As I told you also in the previous blog a remote procedure call is a method to call a function on a remote node and collect the answer.

The most important function in this module is rpc:call(Node, Module, Function, Arguments), it executes the specific function defined in the specific module, with the specified arguments on the node Node and returns the corresponding that can be either the return value, or a tupla of the form {badrpc, Reason}.

As you can see I used the template of a gen_server for my implementation of the counter server. The value of the counter is stored inside its state, and it starts with the value of 0. The server handles a specific call that is aimed to retrieve the counter from the server, increment it by one and return that value to the client. In the internal functions space, I defined a function named count that performs the specific call to the gen_server.

Easy, isn’t it?

Now we have only to start the server in a Erlang node (we name it server@ourlocalhost).

At this point the server is up an running on our Erlang node, so the only thing left is to start another Erlang node (or many nodes) and perform some RPC from these. First of all we start the second node, you should know that this node must be connected to the previous one and share with it the same cookie, if you don’t see Erlang User Guide for more info. In brief I can tell you that you can check whether two nodes are connected by calling in one node the function net:ping(‘othernode@host’) that gives back a ‘pong’ if they are connected, or a ‘pang’ if they are not…..moreover you can check if the nodes have the same cookie by calling in both nodes the function erlang:get_cookie() (otherwise you can set the cookie with erlang:set_cookie(Cookie). Coming back to our discussion on rpc, inside the second node we call the function through RPC by using as stated above rpc:call(Node, Module, Function, Arguments)…in our specific case Node is the node where the server is running, Module is the module implementing the server, Function is the function that retrieves the counter and increments it and Arguments is an empty list, since the function takes no arguments.

conn_manager(Port) is a really simple fuction called in the init function; it does the following: create a tcp socket on the Port passed as argument to the function, this socket will have some features, as you can see we specified that the traffic going trough it is of type binary, that we want the server to send keepalive packets to mantain the connection up and running, that the address may be reused and most importan that this socket will be active once.

What does the active once mean? Well, the socket could have been always active, and this means that we would have been listening to the incoming data without any restrictions…well, sometimes this is a good thing, but think about Denial of Service attacks..we definitely may prefer to listen to the incoming traffic only when neededt…

After the creation of the socket we spawn a new process and pass to it the reference to the socket.

parallel_connection(Listen) is the function spawned as a new process by the previous function. In the very beginning it accepts any incoming connection and checks whether it comes from a blacklisted IP (note that is_in_blacklist is function that I did by myself so it is not a erlang standard function, if the clients in in the blacklist the connection is closed, otherwise we do two things: first we spawn a new parallel_connection function so that new clients may be able to connect to the server, and the we call the function conn_loop(Socket) so that we can manage the traffic coming from the already connected user.

As you can see conn_loop(Socket) is a very basic function…it is a simple receive function that in case of incoming traffic {tcp, Socket, Bin} triggers the socket to receive once more and than with a case construct manages the incoming binaries.

This post was written in a hurry, so if you have questions or comments or anything just comment it or mail me so that I can correct it!

A couple of days ago, I had some time to fix my erlang environment in my new Ubuntu Karmic Koala, so I decided to continue with the development of my cards game in erlang.

If you remember from my previous posts, I did a process for handling the table, it was a gen_server providing a basic interface for a set of actions users may want to perform, as “play a card on the table”, “take a single card/a set of cards from table”, “give me 10 cards” and so on…

This process was also responsible for checking whether the action user wants to do is allowed (e.g. is the card user wants to take in the table), so I thought that next step would have been the creation of another gen_server.

In my mind this server should have listened to a specific port waiting for users; since “scopa” is a game played by 4 users, the server should have waited until 4 users joined the game, than it would have started a new table process for these users.

The last handle_call is used to update the turn list after a player submit an action.

Let’s say that a player sends a command to our server…before forwarding this command to the table we must check whether the user who sent the command is a player of the match and whether he is the player we expect to play (turn); we may want to use two functions like: