Elixir foundationSort Order

Elixir: Render Status Check with Message Passing - [021]

We need to check the status of a rendering to see if it is complete. We'll also need to verify that the rendering is actually completed without errors. In this episode we will implement a new GenServer that we use to check the status of the rendering and send a message back to our rendering engine.

Render Status Module

Let's begin by creating a new GenServer module.

defmodule Botiful.Render.Status do  use GenServer  # Public API  def start_link({agents, owner}) do    GenServer.start_link(__MODULE__, {agents, owner})  end  # Callbacks  def init({agents, owner}) do    {:ok, %{      requests: agents.requests,      responses: agents.responses,       owner: owner    }}  endend

When we start this GenServer we will pass it the agents pid which we will use to check the status of the rendering process and pass it the Botiful.Render.Engine pid so we can send a message back when the rendering is completed.

Scheduling a Check

We will also implement a function that we can call to schedule a check.

defmodule Botiful.Render.Status do  # ...  defp schedule_check() do    Process.send_after(self(), :check, 500)  endend

Next let's implement the callback for the :check .

defmodule Botiful.Render.Status do  # ...  def handle_info(:check, state) do    requests_count = count_calls(state.requests)    responses_count = count_calls(state.responses)    invalid_responses = count_invalid_responses(state.responses)    cond do      requests_count == responses_count && invalid_responses == 0 ->        Process.send(state.owner, :completed_and_valid, [:nosuspend])        {:stop, :normal, state}      requests_count == responses_count        Process.send(state.owner, :completed, [:nosuspend])        {:stop, :normal, state}            true ->        schedule_check()        {:noreply, state}    end  end  defp count_invalid_responses(responses) do    Agent.get(responses, fn calls ->      calls      |> Enum.filter(fn status -> status >= 500 end)      |> Enum.count()    end  end  defp count_calls(pid), do: Agent.get(pid, &Enum.count/1)  # ...end

That concludes our Render Status module. We also need to make sure we call schedule_check when inside init

def init({agents, owner}) do  schedule_check()  {:ok, %{    requests: agents.requests,    responses: agents.responses,     owner: owner  }}end

Basically when the GenServer starts it will schedule a check.