Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/fun_with_flags/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ defmodule FunWithFlags.Config do
end


def cache_adapter do
Keyword.get(ets_cache_config(), :adapter, FunWithFlags.Store.Cache)
end


def ets_cache_config do
Keyword.merge(
@default_cache_config,
Expand Down
9 changes: 4 additions & 5 deletions lib/fun_with_flags/store.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@ defmodule FunWithFlags.Store do
@moduledoc false

require Logger
alias FunWithFlags.Store.Cache
alias FunWithFlags.{Config, Flag, Telemetry}

import FunWithFlags.Config, only: [persistence_adapter: 0]
import FunWithFlags.Config, only: [persistence_adapter: 0, cache_adapter: 0]

@spec lookup(atom) :: {:ok, FunWithFlags.Flag.t}
def lookup(flag_name) do
case Cache.get(flag_name) do
case cache_adapter().get(flag_name) do
{:ok, flag} ->
{:ok, flag}
{:miss, reason, stale_value_or_nil} ->
case persistence_adapter().get(flag_name) do
{:ok, flag} ->
Telemetry.emit_persistence_event({:ok, nil}, :read, flag_name, nil)
Cache.put(flag)
cache_adapter().put(flag)
{:ok, flag}
err = {:error, _reason} ->
Telemetry.emit_persistence_event(err, :read, flag_name, nil)
Expand Down Expand Up @@ -89,7 +88,7 @@ defmodule FunWithFlags.Store do
end

defp cache_persistence_result(result = {:ok, flag}) do
Cache.put(flag)
cache_adapter().put(flag)
result
end

Expand Down
2 changes: 2 additions & 0 deletions lib/fun_with_flags/store/cache.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ defmodule FunWithFlags.Store.Cache do
@type ttl :: integer
@type cached_at :: integer

@behaviour FunWithFlags.Store.Cache.Behaviour

@doc false
use GenServer

Expand Down
55 changes: 55 additions & 0 deletions lib/fun_with_flags/store/cache/behaviour.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
defmodule FunWithFlags.Store.Cache.Behaviour do
@moduledoc """
A behaviour module for implementing cache adapters.

The package ships with a default ETS-based cache adapter (`FunWithFlags.Store.Cache`),
but you can provide your own adapter by adopting this behaviour.

This is useful, for example, to partition cache keys by application in an umbrella
project where multiple OTP apps share the same `fun_with_flags` instance.

## Configuration

config :fun_with_flags, :cache,
enabled: true,
ttl: 900,
adapter: MyApp.CustomCache
"""

@doc """
Returns either a child specification if the cache adapter needs a process
to be started and supervised, or `nil` if it does not.
"""
@callback worker_spec() :: Supervisor.child_spec() | nil

@doc """
Looks up a flag by name in the cache.

Should return:
- `{:ok, flag}` if the flag is found and not expired.
- `{:miss, :not_found, nil}` if the flag is not in the cache.
- `{:miss, :expired, stale_flag}` if the flag is in the cache but expired.
- `{:miss, :invalid, nil}` if the cached entry is invalid.
"""
@callback get(flag_name :: atom) ::
{:ok, FunWithFlags.Flag.t()}
| {:miss, :not_found, nil}
| {:miss, :expired, FunWithFlags.Flag.t()}
| {:miss, :invalid, nil}

@doc """
Stores a flag in the cache.
"""
@callback put(flag :: FunWithFlags.Flag.t()) ::
{:ok, FunWithFlags.Flag.t()}

@doc """
Clears all entries from the cache.
"""
@callback flush() :: true

@doc """
Returns the contents of the cache for inspection and debugging.
"""
@callback dump() :: list()
end
2 changes: 1 addition & 1 deletion lib/fun_with_flags/supervisor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ defmodule FunWithFlags.Supervisor do

defp children do
[
FunWithFlags.Store.Cache.worker_spec(),
Config.cache_adapter().worker_spec(),
persistence_spec(),
notifications_spec(),
]
Expand Down