Search code examples
elixirphoenix-frameworkgen-server

GenServer implementation of an event handler not handling casts


I am trying to use GenServer as an event handler for EventBus in my Phoenix application but for some reason I can't seem to figure out why the handle cast function isn't getting called. I checked that the process was alive with :observer.start().

Is there something I'm missing for the GenServer to handle the cast call correctly?

Essentially the process function is supposed to handle an incoming event and cast it to the GenServer where the GenServer will handle the cast and perform domain logic on that event.

----Gen server module----

defmodule App.Notifications.EventHandler do
  use GenServer
  require Logger


  def start_link(opts \\ []) do
    {:ok, pid} = GenServer.start_link(__MODULE__, [], opts)
  end

  def init([]) do
    {:ok, []}
  end

  def process({topic_id, event_id}) do
    Logger.info("event notification process recieved!!") <---- THIS IS GETTING PRINTED!

    GenServer.cast(__MODULE__, {topic_id, event_id})
  end



def handle_cast({topic_id, event_id}, state) do
  Logger.info("event  notification data Recieved!!") <----- THIS IS NOT

  # do stuff

  {:noreply, state}
end


end

----App module-----

defmodule App.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application


  def start(_type, _args) do

    EventBus.subscribe({App.Notifications.EventHandler, ["^event_notification_created$"]})

    # List all child processes to be supervised
    children = [
      # Start the Ecto repository
      App.Repo,
      # Start the endpoint when the application starts
      AppWeb.Endpoint,
      # Starts a worker by calling: App.Worker.start_link(arg)
      # {App.Worker, arg},,
      App.Notifications.EventHandler <--- STARTING THE GEN SERVER HERE
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: App.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # Tell Phoenix to update the endpoint configuration
  # whenever the application is updated.
  def config_change(changed, _new, removed) do
    App.Endpoint.config_change(changed, removed)
    :ok
  end
end

Solution

  • Documentation on GenServer.cast/2 states, that the first parameter in call to GenServer.cast/2 must be of a type server() which is:

    any of the values described in the “Name registration” section of the documentation for this module.

    In your code you start the link unnamed:

    GenServer.start_link(__MODULE__, [], opts)
    

    but then you cast to the named GenServer:

    #              ⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓
    GenServer.cast(__MODULE__, {topic_id, event_id})
    

    The easiest way to fix it, start the server named:

    GenServer.start_link(__MODULE__, [], name: __MODULE__)