Bitwise
Bitwise

Reputation: 8461

Using a GenServer from another module

I have a simple GenServer and here it is:

GenServer:

defmodule MyApp.ScoreTableQueue do
  use GenServer

  @impl true
  def init(stack) do
    {:ok, stack}
  end

  @impl true
  def handle_call(:pop, _from, state) do
    {:reply, state, []}
  end

  @impl true
  def handle_cast({:push, item}, state) do
    {:noreply, [item | state]}
  end
end

I want to use this GenServer in this module:

MODULE:

  defp order_score(question, season) do
    for team <- season.teams do
      state = score_table_map(question, team)

      # Push state on GenServer queue
    end

    create_score_table(question, season)
  end

  defp score_table_map(question, team) do
    p_score = Enum.find(team.prediction_scores, &(&1.question_id == question.id))
    %{team_score: p_score.score, team_id: p_score.team_id}
  end

  defp create_score_table(question, season) do
    changeset = ScoreTable.changeset(%ScoreTable{
      question_id: question.id,
      season_id: season.id,
      table_details: %{
        information: # Pop state of genserver
      }
    })

    Repo.insert(changeset)
  end

As pointed out in that code example I want to push some state during a loop on the GenServer and after I want to pop the state on the changeset below.

My main question is how do I initialize the genserver in the other module and is this a best practice?

Upvotes: 0

Views: 247

Answers (1)

Justin Wood
Justin Wood

Reputation: 10061

You will not want to initialize the GenServer in another module. You will want to add it to your supervision tree.

You may also want to consider adding "API" functions to your GenServer module so that the users of it do not need to know that it is a GenServer. Something like

# This assumes you have named your GenServer the same as the module name
def push(item) do
  GenServer.call(__MODULE__, {:push, item})
end

def pop() do
  GenServer.call(__MODULE__, :pop)
end

Then you can just call it like normal functions where you need it.

MyApp.ScoreTableQueue.push(:foo)
stack = MyApp.ScoreTableQueue.pop()
...

Upvotes: 4

Related Questions