lib/buzzword/cache/server.ex

defmodule Buzzword.Cache.Server do
  @moduledoc """
  A process that loads a map of buzzwords from an external file and caches it
  for expedient access. The cache is automatically refreshed every hour.
  """

  use GenServer

  alias __MODULE__
  alias Buzzword.Cache.Loader
  alias Buzzword.Cache

  @typedoc "Server state"
  @type state :: {Cache.buzzwords(), reference}

  @refresh_interval :timer.minutes(60)

  @spec start_link(term) :: GenServer.on_start()
  def start_link(:ok = _init_arg),
    do: GenServer.start_link(Server, :ok, name: Server)

  ## Private functions

  @spec state :: state
  defp state do
    {Loader.read_buzzwords(),
     self() |> Process.send_after(:refresh, @refresh_interval)}
  end

  ## Callbacks

  @spec init(term) :: {:ok, state}
  def init(:ok = _init_arg), do: {:ok, state()}

  @spec handle_call(atom, GenServer.from(), state) ::
          {:reply, Cache.buzzwords(), state}
  def handle_call(:get_buzzwords, _from, {buzzwords, _timer_ref} = state),
    do: {:reply, buzzwords, state}

  @spec handle_info(term, state) :: {:noreply, state}
  def handle_info(:refresh, {_buzzwords, timer_ref} = _state) do
    Process.cancel_timer(timer_ref, info: false)
    {:noreply, state()}
  end

  def handle_info(_message, state), do: {:noreply, state}
end