Search code examples
elixirgen-server

Why doesn't my GenServer handle_cast get called


I am using GenServer in my module as below. In the init method, it creates a redis connection to the database. The put method will send values to be saved in redisdb. The handle_cast method will call the command on redis connection to do the database operation.

defmodule RedisClient do
  use GenServer
  require Logger

  # Client
  def start(url, pwd, hkey) do
    GenServer.start(__MODULE__, {url, pwd, hkey});
  end

  def init({url, pwd, hkey}) do
    Logger.info("connect to url #{url} #{pwd} #{hkey}");
    case Redix.start_link(url) do
      {:ok, conn} -> case Redix.command(conn, ["auth", pwd]) do
        {:ok, message} -> {:ok, conn, hkey}
        _ -> {:error}
      end
    end
  end

  def put(pid, field, value) do
    Logger.info("put #{field} #{value}")
    GenServer.cast(pid, {:hset, field, value})
  end

  def handle_cast({:hset, field, value}, {conn, hkey}) do
    Logger.info("write to database #{field} #{value}")
    result = Redix.command(conn, ["hset", hkey, field, value]);
    {:noreply, {conn, hkey}}
  end

end 

Below is the output from iex console. The database connection is established but the handle_cast is not called when I call put method. What is wrong with my implementation?

iex(tbc@192-168-1-7)85> {:ok, pid} = RedisClient.start("redis://localhost", "mypassword", "mykey")
{:ok, #PID<0.23038.0>}
iex(tbc@192-168-1-7)86> 
11:19:49.554 [info]  connect to url redis://localhost mypassword mykey
iex(tbc@192-168-1-7)87> RedisClient.put(pid, "field1", "value1")
:ok
iex(tbc@192-168-1-7)88> 
11:20:26.429 [info]  put field1 value1

Solution

  • Your GenServer is not actually running. If you were to run the following code, you will get the same result.

    iex(1)> {:ok, pid} = RedisClient.start(url, pwd, hkey)
    iex(2)> Process.alive?(pid)
    false
    

    The problem is that you are returning a three element tuple from your GenServer's init/1 callback. The third option is supposed to be a timeout. Your GenServer is crashing when it starts because the hkey is not holding a valid timeout value.

    In your case, you will want to return {:ok, {conn, hkey}} instead.