As we left it, our server works but is ugly to use. Our callers have to make explicit GenServer calls, and they have to know the registered name for our server process. We can do better. Let’s wrap this interface in a set of three functions in our server module: start_link, next_number, and increment_number. The first of these calls the GenServer start_link method. As we’ll see in the next chapter, the name start_link is a convention. start_link must return the correct status values to OTP; as our code simply delegates to the GenServer module, this is taken care of.
Following the definition of start_link, the next two functions are the external API to issue call and cast requests to the running server process.
We’ll also use the name of the module as our server’s registered local name (hence the name: __MODULE__ when we start it, and the __MODULE__ parameter when we use call or cast).
| defmodule Sequence.Server do |
| use GenServer |
| |
| ##### |
| # External API |
| |
» | def start_link(current_number) do |
| GenServer.start_link(__MODULE__, current_number, name: __MODULE__) |
| end |
| |
» | def next_number do |
| GenServer.call __MODULE__, :next_number |
| end |
| |
» | def increment_number(delta) do |
| GenServer.cast __MODULE__, {:increment_number, delta} |
| end |
| |
| ##### |
| # GenServer implementation |
| |
| def init(initial_number) do |
| { :ok, initial_number } |
| end |
| |
| def handle_call(:next_number, _from, current_number) do |
| { :reply, current_number, current_number+1 } |
| end |
| |
| def handle_cast({:increment_number, delta}, current_number) do |
| { :noreply, current_number + delta} |
| end |
| |
| def format_status(_reason, [ _pdict, state ]) do |
| [data: [{'State', "My current state is '#{inspect state}', and I'm happy"}]] |
| end |
| end |
When we run this code in IEx, it’s a lot cleaner:
| $ iex -S mix |
| iex> Sequence.Server.start_link 123 |
| {:ok,#PID<0.57.0>} |
| iex> Sequence.Server.next_number |
| 123 |
| iex> Sequence.Server.next_number |
| 124 |
| iex> Sequence.Server.increment_number 100 |
| :ok |
| iex> Sequence.Server.next_number |
| 225 |
This is the pattern that just about everyone uses in the Elixir world.
I have a different view. However, it certainly isn’t mainstream, so feel free to skip the next section if you want to avoid becoming tainted by my heresies.