Skip to content

Instantly share code, notes, and snippets.

@abhayarawal
Created August 15, 2020 18:57
Show Gist options
  • Select an option

  • Save abhayarawal/a26f38ff4294f2415993979eb975c46d to your computer and use it in GitHub Desktop.

Select an option

Save abhayarawal/a26f38ff4294f2415993979eb975c46d to your computer and use it in GitHub Desktop.
defmodule CacheWorker do
require Logger
defmodule State do
@type t :: %__MODULE__{
hits: integer(),
content: String.t(),
timer: reference()
}
@enforce_keys [:hits, :content, :timer]
defstruct [:hits, :content, :timer]
end
@expire_time 60_000
@spec init(any) :: pid
def init(content) do
spawn(fn ->
timer = Process.send_after(self(), :expire, @expire_time)
Logger.debug(
"#{inspect(self())}: CacheWorker started. Will expire in #{Process.read_timer(timer)} milliseconds."
)
loop(%State{hits: 0, content: content, timer: timer})
end)
end
defp loop(state) do
new_state =
receive do
{:get_content, caller} ->
get_content(state, caller)
:refresh ->
refresh_timer(state)
:expire ->
terminate(state)
message ->
unexpected_message(state, message)
end
loop(new_state)
end
@spec get_content(State.t(), pid()) :: State.t()
defp get_content(%{content: content, hits: hits} = state, caller) do
Logger.debug("Serving request for get_content. Content is #{content}")
send(caller, {:response, content})
new_state = refresh_timer(state)
%{new_state | hits: hits + 1}
end
@spec refresh_timer(State.t()) :: State.t()
defp refresh_timer(%{timer: timer} = state) do
Process.cancel_timer(timer)
new_timer = Process.send_after(self(), :expire, @expire_time)
expires_in = Process.read_timer(new_timer)
Logger.debug(
"#{inspect(self())}: Canceled the previous timer. Will now expire in #{expires_in}"
)
%{state | timer: new_timer}
end
@spec terminate(State.t()) :: true
defp terminate(%{hits: hits}) do
Logger.debug("#{inspect(self())}: Terminating process. Served content #{hits} times")
Process.exit(self(), :normal)
end
@spec unexpected_message(State.t(), any()) :: State.t()
defp unexpected_message(state, message) do
Logger.warn("#{inspect(self())}: Received unexpected message: #{inspect(message)}")
state
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment