Created
August 15, 2020 18:57
-
-
Save abhayarawal/a26f38ff4294f2415993979eb975c46d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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