How to set the GenServer State on fly using :sys module — Elixir/Erlang

Dec 23, 2018 . 2 mins read

This article guides you to set the state of the GenServer on fly using iex

Hello everyone!

No excuse for a programmer to learn something new always. OK! Thoughts are apart. Let’s code.

Why would some one set the state onfly? You may have your own reasons. In my case, I forgot add reset action to my GenServer and pushed the code to production grade level.

Now, the server has gone live. To the client need, now I have to reset the state of the server. OK! Let’s make our client happy :)

Demo GenServer To save our time, I have come up with a simple GenServer code for the demo. It just maintains the state of an employee salary.

Let’s write our server. Create a file demo_server.ex using your favorite editor.

$ vim demo_server.ex

Copy the following code and write to the file you have created before demo_server.ex

defmodule DemoServer do
  use GenServer  

  @vsn 1  

  ## Client API  

  def start_link employee do
      GenServer.start_link __MODULE__, employee, []
  end

  def add_money(pid, value) do
    GenServer.call(pid, {:add, value})
  end  

  ## Server API
  def init(employee) do   # initiating state with passed employee details
    {:ok, employee}
  end

  # add the value to the state and returns :ok
  def handle_call({:add, value},_from, %{name: name, money: money} = state) do
    {:reply, "#{value} added to #{name} ", Map.put(state, :money, money+value)}
  end

end

Now, open the iex and load the file.

$ iex

iex> c "demo_server.ex"
iex> {:ok, pid} = DemoServer.start_link(%{name: "blackode", money: 25000})

iex> DemoServer.add_money, pid, 5000
"5000 added to blackode"

You shall need to be in the same directory of where the demo_server.ex lies. Purposely, I did not write any get handlers here to show you the another way of getting the state using pid.

Now, how do we get the state?

iex> :sys.get_state(pid)
%{name: "blackode", money: 30000}
# here pid is the process identifier of demo_server

iex> DemoServer.add_money(5000)
"5000 added to blackode"

ex> :sys.get_state(pid)
%{name: "blackode", money: 35000}

Now, the client asks you to reset the salary to 0 But, we don’t have the function to call that satisfy the client.

We can still use :sys.replace_state/2 function to replace the state with new_state.

iex> :sys.replace_state pid, fn state -> %{state | money: 0}
%{money: 0, name: "blackode"}


iex> :sys.get_state pid
%{money: 0, name: "blackode"}

I took a silly reason to show you the demo. My only intention is to introduce :sys erlang module. You can use this module to the greater extent once you know how to use it.