Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Elixir Processes and GenServers - Part 4

genservers_4.livemd

Elixir Processes and GenServers - Part 4

7. A Refactored GenServer

First, the business logic.

defmodule Counter.Impl do
  @doc "Pure function: Increment counter"
  def increment(state), do: state + 1

  @doc "Pure function: Decrement counter"
  def decrement(state), do: state - 1

  @doc "Pure function: Get current value"
  def value(state), do: state
end

Next, the GenServer code.

defmodule Counter.Server do
  use GenServer
  alias Counter.Impl

  # Required for GenServer.start_link
  def init(initial_value), do: {:ok, initial_value}

  def handle_cast(:increment, state), do: {:noreply, Impl.increment(state)}
  def handle_cast(:decrement, state), do: {:noreply, Impl.decrement(state)}
  
  def handle_call(:get, _from, state) do
    {:reply, Impl.value(state), state}
  end
end

Finally, the client API.

defmodule Counter do
  @moduledoc "Public API for counter service"

  def start_link(initial_value \\ 0) do
    GenServer.start_link(Counter.Server, initial_value, name: __MODULE__)
  end

  def increment, do: GenServer.cast(__MODULE__, :increment)
  def decrement, do: GenServer.cast(__MODULE__, :decrement)
  def value, do: GenServer.call(__MODULE__, :get)
end

Let’s try it!

{:ok, _pid} = Counter.start_link(10)
Counter.increment()
Counter.decrement()
IO.puts("Counter value: #{Counter.value()}")