Skip to content

Latest commit

 

History

History
245 lines (188 loc) · 7.36 KB

mailbox_server.livemd

File metadata and controls

245 lines (188 loc) · 7.36 KB

Mailbox Server

Mix.install([
  {:jason, "~> 1.4"},
  {:kino, "~> 0.9", override: true},
  {:youtube, github: "brooklinjazz/youtube"},
  {:hidden_cell, github: "brooklinjazz/hidden_cell"}
])

Navigation

Mailbox Server

Earlier you created a Process Mailbox using purely processes. Now you're going to create a similar mailbox using GenServer.

To test your solution, you can use :sys.get_state/1 to get the current state of your mailbox. This should only be used for debugging purposes, not for retrieving values from state in a real-world application.

{:ok, mailbox_pid} = GenServer.start_link(Mailbox, [])

GenServer.cast(mailbox_pid, {:mail, %{title: "Title 1", content: "Content 1"}})
GenServer.cast(mailbox_pid, {:mail, %{title: "Title 2", content: "Content 2"}})

:sys.get_state(mailbox_pid)
[%{title: "Title 2", content: "Content 2"}, %{title: "Title 1", content: "Content 1"}]
Example Solution
defmodule Mailbox do
  use GenServer

  def start_link(state \\ []) do
    GenServer.start_link(__MODULE__, state)
  end

  def send(mailbox_pid, mail) do
    GenServer.cast(mailbox_pid, {:mail, mail})
  end

  def all_messages(mailbox_pid) do
    GenServer.call(mailbox_pid, :all_messages)
  end

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

  @impl true
  def handle_call(:all_messages, _from, state) do
    {:noreply, state, state}
  end

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

  def handle_info({:mail, mail}, state) do
    {:noreply, [mail | state]}
  end
end

Implement the Mailbox GenServer as documented below.

defmodule Mailbox do
  use GenServer

  @doc """
  Start a mailbox server.

  ## Examples

      iex> {:ok, pid} = Mailbox.start_link([])
      iex> :sys.get_state(pid)
      []

      Allow the mailbox to start with a default list of messages.

      iex> {:ok, pid} = Mailbox.start_link(["Welcome to your mailbox!"])
      iex> :sys.get_state(pid)
      ["Welcome to your mailbox!"]
  """
  def start_link(_opts) do
  end

  @doc """
  Asynchronously Send a message to a mailbox server.

  ## Examples

      iex> {:ok, pid} = Mailbox.start_link([])
      iex> Mailbox.send(pid, "Message 1")
      iex> Mailbox.send(pid, "Message 2")
      iex> :sys.get_state(pid)
      ["Message 2", "Message 1"]
  """
  def send(mailbox_pid, message) do
  end

  @doc """
  Synchonously retrieve all messages in a mailbox server.

  ## Examples

      iex> {:ok, pid} = Mailbox.start_link([])
      iex> Mailbox.all_messages(pid)
      []
  """
  def all_messages(mailbox_pid) do
  end

  @doc """
  Required callback to start a GenServer.

  ## Examples

      iex> {:ok, _pid} = GenServer.start_link(Mailbox, [])
  """
  @impl true
  def init(state) do
  end

  @doc """
  Callback to synchronously retrieve a `Mailbox`'s state.

  ## Examples

      iex> {:ok, pid} = GenServer.start_link(Mailbox, ["Welcome"])
      iex> GenServer.call(pid, :all_messages)
      ["Welcome"]
  """
  @impl true
  def handle_call(:all_messages, _from, state) do
  end

  @doc """
  Callback for receiving a `cast` message and storing it in the `Mailbox`'s state.

  ## Examples

      iex> {:ok, pid} = GenServer.start_link(Mailbox, [])
      iex> GenServer.cast(pid, {:mail, "Message 1"})
      iex> GenServer.cast(pid, {:mail, "Message 2"})
      iex> :sys.get_state(pid)
      ["Message 2", "Message 1"]
  """
  @impl true
  def handle_cast({:mail, mail}, state) do
  end

  @doc """
  Callback for receiving "regular" messages and storing them in the `Mailbox`'s state.

  ## Examples

      iex> {:ok, pid} = GenServer.start_link(Mailbox, [])
      iex> Process.send(pid, {:mail, "Message 1"}, [])
      iex> Process.send(pid, {:mail, "Message 2"}, [])
      iex> :sys.get_state(pid)
      ["Message 2", "Message 1"]
  """
  @impl true
  def handle_info({:mail, mail}, state) do
  end
end

handle_info Vs handle_cast/handle_call

The main difference between these functions is how you call them.

You call handle_cast with GenServer.cast and handle_call with GenServer.call. handle_info is called with Process.send.

It is useful for situations where you don't have access to GenServer.call or when you need to send a message to many different GenServers without calling a bunch of different functions to do it.

Commit Your Progress

DockYard Academy now recommends you use the latest Release rather than forking or cloning our repository.

Run git status to ensure there are no undesirable changes. Then run the following in your command line from the curriculum folder to commit your progress.

$ git add .
$ git commit -m "finish Mailbox Server exercise"
$ git push

We're proud to offer our open-source curriculum free of charge for anyone to learn from at their own pace.

We also offer a paid course where you can learn from an instructor alongside a cohort of your peers. We will accept applications for the June-August 2023 cohort soon.

Navigation