An implementation with ets.
Let’s start with implementation
defmodule SimpleCache do
@table :simple_cache
def init(_) do
:ets.new(@table, [
:set,
:named_table,
:public,
read_concurrency: true,
write_concurrency: true
])
{:ok, %{}}
end
def start_link do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def fetch(key, expires_in_seconds, fun) do
case lookup(key) do
{:hit, value} ->
value
:miss ->
value = fun.()
put(key, expires_in_seconds, value)
value
end
end
defp lookup(key) do
case :ets.lookup(@table, key) do
[{^key, expires_at, value}] ->
case now < expires_at do
true -> {:hit, value}
false -> :miss
end
_ ->
:miss
end
end
defp put(key, expires_in_seconds, value) do
expires_at = now + expires_in_seconds
:ets.insert(@table, {key, expires_at, value})
end
defp now do
:erlang.system_time(:seconds)
end
end
Update application.ex
def start(_type, _args) do
import Supervisor.Spec
children = [
supervisor(SimpleCache, [])
]
opts = [strategy: :one_for_one, name: Supervisor]
Supervisor.start_link(children, opts)
end
Finally, use it
cache_for_seconds = 60
key = 'key'
SimpleCache.fetch(key, cache_for_seconds, fn ->
{:ok, some_expensive_operation}
end)
Relavent links:
https://stackoverflow.com/questions/35218738/caching-expensive-computation-in-elixir
https://dockyard.com/blog/2017/05/19/optimizing-elixir-and-phoenix-with-ets

