GenServer

GenServer is an OTP protocol. OTP works by assuming that our module defines a number of callback functions. There are six in the case of a GenServer. If we were writing a GenServer in Erlang, our code would have to contain implementations of all six functions.

When we add the statement use GenServer to a module, Elixir creates default implementations of these six callback functions. All we have to do is override the ones where we add our own application-specific behavior. Our examples so far have used the three callbacks init, handle_call, and handle_cast. Here, we’ll look at the full list.

init(start_arguments)

GenServer calls init(start_arguments) when starting a new server. The parameter is the second argument passed to start_link. It should return {:ok, state} on success, or {:stop, reason} if the server couldn’t be started.

We can specify an optional timeout using {:ok, state, timeout}, in which case GenServer sends the process a :timeout message whenever no message is received in a span of timeout microseconds. The message is passed to the handle_info function.

The default GenServer implementation sets the server state to the argument we pass.

handle_call(request, from, state)

The handle_call(request, from, state) callback function is invoked when a client uses GenServer.call(pid, request). The from parameter is a tuple containing the PID of the client and a unique tag. The state parameter is the server state. On success, it returns {:reply, result, new_state}.

The default implementation stops the server with a :bad_call error, so we’ll need to implement handle_call for every call request type our server implements.

handle_cast(request, state)

The handle_cast(request, state) callback function is called in response to GenServer.cast(pid, request).

A successful response is {:noreply, new_state}. It can also return {:stop, reason, new_state}. The default implementation stops the server with a :bad_cast error.

handle_info(info, state)

The handle_info(info, state) callback function is called to handle incoming messages that don’t call or cast requests. For example, timeout messages are handled here. So are termination messages from any linked processes. In addition, messages sent to the PID using send (so they bypass GenServer) are routed to this function.

terminate(reason, state)

The terminate(reason, state) callback function is called when the server is about to be terminated. However, as we’ll discuss in the next chapter, once we add supervision to our servers, we don’t have to worry about this.

code_change(from_version, state, extra)

The code_change(from_version, state, extra) callback function updates a running server without stopping the system. However, the new version of the server may represent its state differently from the old version. The code_change callback is invoked to change from the old state format to the new.

format_status(reason, [pdict, state])

The format_status(reason, [pdict, state]) callback function is used to customize the state display of the server. The conventional response is [data: [{'State', state_info}]].

The call and cast handlers return standardized responses. Some of these responses can contain an optional :hibernate or timeout parameter. If hibernate is returned, the server state is removed from memory but is recovered on the next request. This saves memory at the expense of some CPU. The timeout option can be the atom :infinite (which is the default) or a number. If it’s the latter, a :timeout message is sent if the server is idle for the specified number of milliseconds.

The first two responses are common between call and cast.

{ :noreply, new_state [ , :hibernate | timeout ] }

{ :stop, reason, new_state }

The { :stop, reason, new_state } callback function gives the signal that the server is to terminate.

Only handle_call can use the last two.

{ :reply, response, new_state [ , :hibernate | timeout ] }

The { :reply, response, new_state [ , :hibernate | timeout ] } callback function sends response to the client.

{ :stop, reason, reply, new_state }

The { :stop, reason, reply, new_state } callback function sends the response and signal that the server is to terminate.

Get hands-on with 1400+ tech skills courses.