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

GenServer

genserver.livemd

GenServer

Section

defmodule Bomb do
  use GenServer

  def start_link(opts) do
    name = Keyword.get(opts, :name)
    IO.inspect(opts, label: "GENSERVER #{name} WAS STARTED")
    GenServer.start_link(__MODULE__, "init arg", name: __MODULE__)
  end

  def init(init_arg) do
    IO.inspect(init_arg, label: "INIT FUNCTION WAS CALLED")
    {:ok, []}
  end

  def handle_call(:detonate, _from, state) do
    IO.inspect("detonate!")
    {:reply, state, state}
  end

  def handle_info(:detonate, state) do
    IO.inspect("detonating!")
    {:noreply, state}
  end
end
{:ok, pid} = Bomb.start_link([])
GenServer.call(pid, :detonate)
Process.send(Bomb, :detonate, [])
defmodule Counter do
  use GenServer

  def start_link(opts) do
    IO.inspect(opts, label: "GENSERVER WAS STARTED")
    GenServer.start_link(__MODULE__, opts)
  end

  @impl true
  def init(init_arg) do
    IO.inspect(init_arg, label: "INIT FUNCTION WAS CALLED")
    {:ok, init_arg}
  end

  @impl true
  def handle_info(:increment, state) do
    next_state = state + 1
    IO.inspect(state, label: "incrementing to #{next_state}")
    {:noreply, next_state}
  end
end
GenServer.start_link(Counter, 0)
{:ok, pid} = Counter.start_link(10)
Process.send(pid, :increment, [])

Traffic Light Server

defmodule TrafficLightClientAPI do
  def start_link(_opts) do
    GenServer.start_link(TrafficLightServerCallbacks, [])
  end

  def transition(pid) do
    GenServer.call(pid, :switch)
  end
end

defmodule TrafficLightServerCallbacks do
  use GenServer

  def init(_opts) do
    {:ok, :green}
  end

  def handle_call(:switch, _from, state) do
    next_light =
      case state do
        :green -> :yellow
        :yellow -> :red
        :red -> :green
      end

    {:reply, next_light, next_light}
  end
end

Call vs Cast

Server Callback vs Client API

defmodule Counter do
  use GenServer

  # Server Callbacks

  def init(_opts) do
    IO.puts("Counter Initialized")
    {:ok, 0}
  end

  # synchronous get_count
  def handle_cast(:increment, state) do
    GenServer.cast(self(), :log_count)
    {:noreply, state + 1}
  end

  def handle_cast(:log_count, state) do
    IO.inspect(state, label: "CURRENT COUNT")
    {:noreply, state}
  end
end
{:ok, pid} = GenServer.start_link(Counter, [])
GenServer.cast(pid, :increment)
:sys.get_state(pid)