mirror of
https://github.com/plausible/analytics.git
synced 2024-09-11 18:07:33 +03:00
* Reapply "Replace caching engine (#3878)" (#3883)
This reverts commit c5881cdc6d
.
* Ensure hit rate is tracked on `get_or_store`
* Remove :wx and :observer
* Remove unused deps
* Use `:set` table type
This commit is contained in:
parent
e8f3946dde
commit
59afa20955
@ -10,6 +10,7 @@ defmodule Plausible.Application do
|
||||
on_full_build(do: Plausible.License.ensure_valid_license())
|
||||
|
||||
children = [
|
||||
Plausible.Cache.Stats,
|
||||
Plausible.Repo,
|
||||
Plausible.ClickhouseRepo,
|
||||
Plausible.IngestRepo,
|
||||
@ -23,13 +24,15 @@ defmodule Plausible.Application do
|
||||
Supervisor.child_spec(Plausible.Event.WriteBuffer, id: Plausible.Event.WriteBuffer),
|
||||
Supervisor.child_spec(Plausible.Session.WriteBuffer, id: Plausible.Session.WriteBuffer),
|
||||
ReferrerBlocklist,
|
||||
Supervisor.child_spec({Cachex, name: :user_agents, limit: 10_000, stats: true},
|
||||
id: :cachex_user_agents
|
||||
Plausible.Cache.Adapter.child_spec(:user_agents, :cache_user_agents,
|
||||
ttl_check_interval: :timer.seconds(5),
|
||||
global_ttl: :timer.minutes(60)
|
||||
),
|
||||
Supervisor.child_spec({Cachex, name: :sessions, limit: nil, stats: true},
|
||||
id: :cachex_sessions
|
||||
Plausible.Cache.Adapter.child_spec(:sessions, :cache_sessions,
|
||||
ttl_check_interval: :timer.seconds(1),
|
||||
global_ttl: :timer.minutes(30)
|
||||
),
|
||||
{Plausible.Site.Cache, []},
|
||||
{Plausible.Site.Cache, ttl_check_interval: false},
|
||||
{Plausible.Cache.Warmer,
|
||||
[
|
||||
child_name: Plausible.Site.Cache.All,
|
||||
@ -44,7 +47,7 @@ defmodule Plausible.Application do
|
||||
interval: :timer.seconds(30),
|
||||
warmer_fn: :refresh_updated_recently
|
||||
]},
|
||||
{Plausible.Shield.IPRuleCache, []},
|
||||
{Plausible.Shield.IPRuleCache, ttl_check_interval: false},
|
||||
{Plausible.Cache.Warmer,
|
||||
[
|
||||
child_name: Plausible.Shield.IPRuleCache.All,
|
||||
@ -59,7 +62,7 @@ defmodule Plausible.Application do
|
||||
interval: :timer.seconds(35),
|
||||
warmer_fn: :refresh_updated_recently
|
||||
]},
|
||||
{Plausible.Shield.CountryRuleCache, []},
|
||||
{Plausible.Shield.CountryRuleCache, ttl_check_interval: false},
|
||||
{Plausible.Cache.Warmer,
|
||||
[
|
||||
child_name: Plausible.Shield.CountryRuleCache.All,
|
||||
@ -168,16 +171,6 @@ defmodule Plausible.Application do
|
||||
)
|
||||
end
|
||||
|
||||
def report_cache_stats() do
|
||||
case Cachex.stats(:user_agents) do
|
||||
{:ok, stats} ->
|
||||
Logger.info("User agent cache stats: #{inspect(stats)}")
|
||||
|
||||
e ->
|
||||
IO.puts("Unable to show cache stats: #{inspect(e)}")
|
||||
end
|
||||
end
|
||||
|
||||
defp setup_opentelemetry() do
|
||||
OpentelemetryPhoenix.setup()
|
||||
OpentelemetryEcto.setup([:plausible, :repo])
|
||||
|
@ -8,10 +8,10 @@ defmodule Plausible.Cache do
|
||||
# - Optionally override `unwrap_cache_keys/1`
|
||||
# - Populate the cache with `Plausible.Cache.Warmer`
|
||||
|
||||
Serves as a thin wrapper around Cachex, but the underlying
|
||||
Serves as a wrapper around `Plausible.Cache.Adapter`, where the underlying
|
||||
implementation can be transparently swapped.
|
||||
|
||||
Even though the Cachex process is started, cache access is disabled
|
||||
Even though normally the relevant Adapter processes are started, cache access is disabled
|
||||
during tests via the `:plausible, #{__MODULE__}, enabled: bool()` application env key.
|
||||
This can be overridden on case by case basis, using the child specs options.
|
||||
|
||||
@ -61,29 +61,33 @@ defmodule Plausible.Cache do
|
||||
@behaviour Plausible.Cache
|
||||
@modes [:all, :updated_recently]
|
||||
|
||||
alias Plausible.Cache.Adapter
|
||||
|
||||
@spec get(any(), Keyword.t()) :: any() | nil
|
||||
def get(key, opts \\ []) do
|
||||
def get(key, opts \\ []) when is_list(opts) do
|
||||
cache_name = Keyword.get(opts, :cache_name, name())
|
||||
force? = Keyword.get(opts, :force?, false)
|
||||
|
||||
if Plausible.Cache.enabled?() or force? do
|
||||
case Cachex.get(cache_name, key) do
|
||||
{:ok, nil} ->
|
||||
nil
|
||||
|
||||
{:ok, item} ->
|
||||
item
|
||||
|
||||
{:error, e} ->
|
||||
Logger.error("Error retrieving key from '#{inspect(cache_name)}': #{inspect(e)}")
|
||||
|
||||
nil
|
||||
end
|
||||
Adapter.get(cache_name, key)
|
||||
else
|
||||
get_from_source(key)
|
||||
end
|
||||
end
|
||||
|
||||
@spec get_or_store(any(), (-> any()), Keyword.t()) :: any() | nil
|
||||
def get_or_store(key, fallback_fn, opts \\ [])
|
||||
when is_function(fallback_fn, 0) and is_list(opts) do
|
||||
cache_name = Keyword.get(opts, :cache_name, name())
|
||||
force? = Keyword.get(opts, :force?, false)
|
||||
|
||||
if Plausible.Cache.enabled?() or force? do
|
||||
Adapter.get(cache_name, key, fallback_fn)
|
||||
else
|
||||
get_from_source(key) || fallback_fn.()
|
||||
end
|
||||
end
|
||||
|
||||
def unwrap_cache_keys(items), do: items
|
||||
defoverridable unwrap_cache_keys: 1
|
||||
|
||||
@ -117,10 +121,10 @@ defmodule Plausible.Cache do
|
||||
def merge_items(new_items, opts) do
|
||||
new_items = unwrap_cache_keys(new_items)
|
||||
cache_name = Keyword.get(opts, :cache_name, name())
|
||||
true = Cachex.put_many!(cache_name, new_items)
|
||||
:ok = Adapter.put_many(cache_name, new_items)
|
||||
|
||||
if Keyword.get(opts, :delete_stale_items?, true) do
|
||||
{:ok, old_keys} = Cachex.keys(cache_name)
|
||||
old_keys = Adapter.keys(cache_name)
|
||||
|
||||
new = MapSet.new(Enum.into(new_items, [], fn {k, _} -> k end))
|
||||
old = MapSet.new(old_keys)
|
||||
@ -128,7 +132,7 @@ defmodule Plausible.Cache do
|
||||
old
|
||||
|> MapSet.difference(new)
|
||||
|> Enum.each(fn k ->
|
||||
Cachex.del(cache_name, k)
|
||||
Adapter.delete(cache_name, k)
|
||||
end)
|
||||
end
|
||||
|
||||
@ -139,11 +143,7 @@ defmodule Plausible.Cache do
|
||||
def child_spec(opts) do
|
||||
cache_name = Keyword.get(opts, :cache_name, name())
|
||||
child_id = Keyword.get(opts, :child_id, child_id())
|
||||
|
||||
Supervisor.child_spec(
|
||||
{Cachex, name: cache_name, limit: nil, stats: true},
|
||||
id: child_id
|
||||
)
|
||||
Adapter.child_spec(cache_name, child_id, opts)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@ -154,7 +154,7 @@ defmodule Plausible.Cache do
|
||||
@spec ready?(atom()) :: boolean
|
||||
def ready?(cache_name \\ name()) do
|
||||
case size(cache_name) do
|
||||
n when n > 0 ->
|
||||
n when is_integer(n) and n > 0 ->
|
||||
true
|
||||
|
||||
0 ->
|
||||
@ -165,21 +165,8 @@ defmodule Plausible.Cache do
|
||||
end
|
||||
end
|
||||
|
||||
@spec size() :: non_neg_integer()
|
||||
def size(cache_name \\ name()) do
|
||||
case Cachex.size(cache_name) do
|
||||
{:ok, size} -> size
|
||||
_ -> 0
|
||||
end
|
||||
end
|
||||
|
||||
@spec hit_rate() :: number()
|
||||
def hit_rate(cache_name \\ name()) do
|
||||
case Cachex.stats(cache_name) do
|
||||
{:ok, stats} -> Map.get(stats, :hit_rate, 0)
|
||||
_ -> 0
|
||||
end
|
||||
end
|
||||
defdelegate size(cache_name \\ name()), to: Plausible.Cache.Adapter
|
||||
defdelegate hit_rate(cache_name \\ name()), to: Plausible.Cache.Stats
|
||||
|
||||
@spec telemetry_event_refresh(atom(), atom()) :: list(atom())
|
||||
def telemetry_event_refresh(cache_name \\ name(), mode) when mode in @modes do
|
||||
|
136
lib/plausible/cache/adapter.ex
vendored
Normal file
136
lib/plausible/cache/adapter.ex
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
defmodule Plausible.Cache.Adapter do
|
||||
@moduledoc """
|
||||
Interface for the underlying cache implementation.
|
||||
Currently: ConCache
|
||||
|
||||
Using the Adapter module directly, the user must ensure that the relevant
|
||||
processes are available to use, which is normally done via the child specification.
|
||||
"""
|
||||
|
||||
require Logger
|
||||
|
||||
@spec child_spec(atom(), atom(), Keyword.t()) :: Supervisor.child_spec()
|
||||
def child_spec(name, child_id, opts \\ [])
|
||||
when is_atom(name) and is_atom(child_id) and is_list(opts) do
|
||||
cache_name = Keyword.get(opts, :cache_name, name)
|
||||
child_id = Keyword.get(opts, :child_id, child_id)
|
||||
ttl_check_interval = Keyword.get(opts, :ttl_check_interval, false)
|
||||
|
||||
opts =
|
||||
opts
|
||||
|> Keyword.put(:name, cache_name)
|
||||
|> Keyword.put(:ttl_check_interval, ttl_check_interval)
|
||||
|
||||
Supervisor.child_spec(
|
||||
{ConCache, opts},
|
||||
id: child_id
|
||||
)
|
||||
end
|
||||
|
||||
@spec size(atom()) :: non_neg_integer() | nil
|
||||
def size(cache_name) do
|
||||
ConCache.size(cache_name)
|
||||
catch
|
||||
:exit, _ -> nil
|
||||
end
|
||||
|
||||
@spec get(atom(), any()) :: any()
|
||||
def get(cache_name, key) do
|
||||
result = ConCache.get(cache_name, key)
|
||||
if is_nil(result), do: miss(cache_name), else: hit(cache_name)
|
||||
result
|
||||
catch
|
||||
:exit, _ ->
|
||||
Logger.error("Error retrieving key from '#{inspect(cache_name)}'")
|
||||
nil
|
||||
end
|
||||
|
||||
@spec get(atom(), any(), (-> any())) :: any()
|
||||
def get(cache_name, key, fallback_fn) do
|
||||
cache = ConCache.Owner.cache(cache_name)
|
||||
|
||||
case ConCache.Operations.get(cache, key) do
|
||||
nil ->
|
||||
get_or_store_isolated(cache, cache_name, key, fallback_fn)
|
||||
|
||||
value ->
|
||||
hit(cache_name)
|
||||
value
|
||||
end
|
||||
catch
|
||||
:exit, _ ->
|
||||
Logger.error("Error retrieving key from '#{inspect(cache_name)}'")
|
||||
nil
|
||||
end
|
||||
|
||||
@spec put(atom(), any(), any()) :: any()
|
||||
def put(cache_name, key, value) do
|
||||
:ok = ConCache.put(cache_name, key, value)
|
||||
value
|
||||
catch
|
||||
:exit, _ ->
|
||||
Logger.error("Error putting a key to '#{cache_name}'")
|
||||
nil
|
||||
end
|
||||
|
||||
@spec put_many(atom(), [any()]) :: :ok
|
||||
def put_many(cache_name, items) when is_list(items) do
|
||||
true = :ets.insert(ConCache.ets(cache_name), items)
|
||||
:ok
|
||||
catch
|
||||
:exit, _ ->
|
||||
Logger.error("Error putting keys to '#{cache_name}'")
|
||||
:ok
|
||||
end
|
||||
|
||||
@spec delete(atom(), any()) :: :ok
|
||||
def delete(cache_name, key) do
|
||||
ConCache.dirty_delete(cache_name, key)
|
||||
catch
|
||||
:exit, _ ->
|
||||
Logger.error("Error deleting a key in '#{cache_name}'")
|
||||
:ok
|
||||
end
|
||||
|
||||
@spec keys(atom()) :: Enumerable.t()
|
||||
def keys(cache_name) do
|
||||
ets = ConCache.ets(cache_name)
|
||||
|
||||
Stream.resource(
|
||||
fn -> :ets.first(ets) end,
|
||||
fn
|
||||
:"$end_of_table" -> {:halt, nil}
|
||||
prev_key -> {[prev_key], :ets.next(ets, prev_key)}
|
||||
end,
|
||||
fn _ -> :ok end
|
||||
)
|
||||
catch
|
||||
:exit, _ ->
|
||||
Logger.error("Error retrieving key from '#{inspect(cache_name)}'")
|
||||
[]
|
||||
end
|
||||
|
||||
defp hit(cache_name) do
|
||||
Plausible.Cache.Stats.record_hit(cache_name)
|
||||
end
|
||||
|
||||
defp miss(cache_name) do
|
||||
Plausible.Cache.Stats.record_miss(cache_name)
|
||||
end
|
||||
|
||||
defp get_or_store_isolated(cache, cache_name, key, fun) do
|
||||
ConCache.isolated(cache_name, key, fn ->
|
||||
case ConCache.Operations.get(cache, key) do
|
||||
nil ->
|
||||
new_value = fun.()
|
||||
ConCache.Operations.dirty_put(cache, key, new_value)
|
||||
miss(cache_name)
|
||||
new_value
|
||||
|
||||
existing ->
|
||||
hit(cache_name)
|
||||
existing
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
84
lib/plausible/cache/stats.ex
vendored
Normal file
84
lib/plausible/cache/stats.ex
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
defmodule Plausible.Cache.Stats do
|
||||
@moduledoc """
|
||||
Keeps track of hit/miss ratio for various caches.
|
||||
"""
|
||||
|
||||
use GenServer
|
||||
|
||||
@hit :hit
|
||||
@miss :miss
|
||||
@telemetry_hit [:plausible, :cache, :adapter, @hit]
|
||||
@telemetry_miss [:plausible, :cache, :adapter, @miss]
|
||||
@telemetry_events [@telemetry_hit, @telemetry_miss]
|
||||
|
||||
def start_link(_opts) do
|
||||
GenServer.start_link(__MODULE__, nil)
|
||||
end
|
||||
|
||||
def record_hit(cache_name) do
|
||||
:telemetry.execute(@telemetry_hit, %{}, %{cache_name: cache_name})
|
||||
end
|
||||
|
||||
def record_miss(cache_name) do
|
||||
:telemetry.execute(@telemetry_miss, %{}, %{cache_name: cache_name})
|
||||
end
|
||||
|
||||
def init(nil) do
|
||||
__MODULE__ =
|
||||
:ets.new(__MODULE__, [
|
||||
:public,
|
||||
:named_table,
|
||||
:set,
|
||||
read_concurrency: true,
|
||||
write_concurrency: true
|
||||
])
|
||||
|
||||
:telemetry.attach_many(
|
||||
"plausible-cache-stats",
|
||||
@telemetry_events,
|
||||
&__MODULE__.handle_telemetry_event/4,
|
||||
nil
|
||||
)
|
||||
|
||||
{:ok, nil}
|
||||
end
|
||||
|
||||
def handle_telemetry_event(@telemetry_hit, _measurments, %{cache_name: cache_name}, _) do
|
||||
bump(cache_name, @hit)
|
||||
end
|
||||
|
||||
def handle_telemetry_event(@telemetry_miss, _measurments, %{cache_name: cache_name}, _) do
|
||||
bump(cache_name, @miss)
|
||||
end
|
||||
|
||||
def gather(cache_name) do
|
||||
{:ok,
|
||||
%{
|
||||
hit_rate: hit_rate(cache_name),
|
||||
count: size(cache_name) || 0
|
||||
}}
|
||||
end
|
||||
|
||||
defdelegate size(cache_name), to: Plausible.Cache.Adapter
|
||||
|
||||
def bump(cache_name, type) do
|
||||
:ets.update_counter(
|
||||
__MODULE__,
|
||||
{cache_name, type},
|
||||
1,
|
||||
{{cache_name, type}, 0}
|
||||
)
|
||||
end
|
||||
|
||||
def hit_rate(cache_name) do
|
||||
hit = :ets.lookup_element(__MODULE__, {cache_name, @hit}, 2, 0)
|
||||
miss = :ets.lookup_element(__MODULE__, {cache_name, @miss}, 2, 0)
|
||||
hit_miss = hit + miss
|
||||
|
||||
if hit_miss == 0 do
|
||||
0.0
|
||||
else
|
||||
hit / hit_miss * 100
|
||||
end
|
||||
end
|
||||
end
|
@ -388,11 +388,9 @@ defmodule Plausible.Ingestion.Event do
|
||||
end
|
||||
|
||||
defp parse_user_agent(%Request{user_agent: user_agent}) when is_binary(user_agent) do
|
||||
case Cachex.fetch(:user_agents, user_agent, &UAInspector.parse/1) do
|
||||
{:ok, user_agent} -> user_agent
|
||||
{:commit, user_agent} -> user_agent
|
||||
_ -> nil
|
||||
end
|
||||
Plausible.Cache.Adapter.get(:user_agents, user_agent, fn ->
|
||||
UAInspector.parse(user_agent)
|
||||
end)
|
||||
end
|
||||
|
||||
defp parse_user_agent(request), do: request
|
||||
|
@ -19,27 +19,22 @@ defmodule Plausible.Session.CacheStore do
|
||||
defp find_session(_domain, nil), do: nil
|
||||
|
||||
defp find_session(event, user_id) do
|
||||
from_cache = Cachex.get(:sessions, {event.site_id, user_id})
|
||||
from_cache = Plausible.Cache.Adapter.get(:sessions, {event.site_id, user_id})
|
||||
|
||||
case from_cache do
|
||||
{:ok, nil} ->
|
||||
nil ->
|
||||
nil
|
||||
|
||||
{:ok, session} ->
|
||||
session ->
|
||||
if Timex.diff(event.timestamp, session.timestamp, :minutes) <= 30 do
|
||||
session
|
||||
end
|
||||
|
||||
{:error, e} ->
|
||||
Sentry.capture_message("Cachex error", extra: %{error: e})
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
defp persist_session(session) do
|
||||
key = {session.site_id, session.user_id}
|
||||
Cachex.put(:sessions, key, session, ttl: :timer.minutes(30))
|
||||
session
|
||||
Plausible.Cache.Adapter.put(:sessions, key, session)
|
||||
end
|
||||
|
||||
defp update_session(session, event) do
|
||||
|
@ -19,7 +19,7 @@ defmodule Plausible.Shield.CountryRuleCache do
|
||||
def name(), do: @cache_name
|
||||
|
||||
@impl true
|
||||
def child_id(), do: :cachex_country_blocklist
|
||||
def child_id(), do: :cache_country_blocklist
|
||||
|
||||
@impl true
|
||||
def count_all() do
|
||||
|
@ -19,7 +19,7 @@ defmodule Plausible.Shield.IPRuleCache do
|
||||
def name(), do: @cache_name
|
||||
|
||||
@impl true
|
||||
def child_id(), do: :cachex_ip_blocklist
|
||||
def child_id(), do: :cache_ip_blocklist
|
||||
|
||||
@impl true
|
||||
def count_all() do
|
||||
|
@ -37,7 +37,7 @@ defmodule Plausible.Site.Cache do
|
||||
def name(), do: @cache_name
|
||||
|
||||
@impl true
|
||||
def child_id(), do: :cachex_sites
|
||||
def child_id(), do: :cache_sites
|
||||
|
||||
@impl true
|
||||
def count_all() do
|
||||
|
@ -88,29 +88,23 @@ defmodule Plausible.PromEx.Plugins.PlausibleMetrics do
|
||||
end
|
||||
|
||||
@doc """
|
||||
Add telemetry events for Cachex user agents and sessions
|
||||
Fire telemetry events for various caches
|
||||
"""
|
||||
def execute_cache_metrics do
|
||||
{:ok, user_agents_stats} = Cachex.stats(:user_agents)
|
||||
{:ok, sessions_stats} = Cachex.stats(:sessions)
|
||||
{:ok, user_agents_stats} = Plausible.Cache.Stats.gather(:user_agents)
|
||||
{:ok, sessions_stats} = Plausible.Cache.Stats.gather(:sessions)
|
||||
|
||||
user_agents_hit_rate = Map.get(user_agents_stats, :hit_rate, 0.0)
|
||||
sessions_hit_rate = Map.get(sessions_stats, :hit_rate, 0.0)
|
||||
|
||||
{:ok, user_agents_count} = Cachex.size(:user_agents)
|
||||
{:ok, sessions_count} = Cachex.size(:sessions)
|
||||
|
||||
:telemetry.execute([:prom_ex, :plugin, :cachex, :user_agents], %{
|
||||
count: user_agents_count,
|
||||
hit_rate: user_agents_hit_rate
|
||||
:telemetry.execute([:prom_ex, :plugin, :cache, :user_agents], %{
|
||||
count: user_agents_stats.count,
|
||||
hit_rate: user_agents_stats.hit_rate
|
||||
})
|
||||
|
||||
:telemetry.execute([:prom_ex, :plugin, :cachex, :sessions], %{
|
||||
count: sessions_count,
|
||||
hit_rate: sessions_hit_rate
|
||||
:telemetry.execute([:prom_ex, :plugin, :cache, :sessions], %{
|
||||
count: sessions_stats.count,
|
||||
hit_rate: sessions_stats.hit_rate
|
||||
})
|
||||
|
||||
:telemetry.execute([:prom_ex, :plugin, :cachex, :sites], %{
|
||||
:telemetry.execute([:prom_ex, :plugin, :cache, :sites], %{
|
||||
count: Site.Cache.size(),
|
||||
hit_rate: Site.Cache.hit_rate()
|
||||
})
|
||||
@ -144,32 +138,32 @@ defmodule Plausible.PromEx.Plugins.PlausibleMetrics do
|
||||
[
|
||||
last_value(
|
||||
metric_prefix ++ [:cache, :sessions, :size],
|
||||
event_name: [:prom_ex, :plugin, :cachex, :sessions],
|
||||
event_name: [:prom_ex, :plugin, :cache, :sessions],
|
||||
measurement: :count
|
||||
),
|
||||
last_value(
|
||||
metric_prefix ++ [:cache, :user_agents, :size],
|
||||
event_name: [:prom_ex, :plugin, :cachex, :user_agents],
|
||||
event_name: [:prom_ex, :plugin, :cache, :user_agents],
|
||||
measurement: :count
|
||||
),
|
||||
last_value(
|
||||
metric_prefix ++ [:cache, :user_agents, :hit_ratio],
|
||||
event_name: [:prom_ex, :plugin, :cachex, :user_agents],
|
||||
event_name: [:prom_ex, :plugin, :cache, :user_agents],
|
||||
measurement: :hit_rate
|
||||
),
|
||||
last_value(
|
||||
metric_prefix ++ [:cache, :sessions, :hit_ratio],
|
||||
event_name: [:prom_ex, :plugin, :cachex, :sessions],
|
||||
event_name: [:prom_ex, :plugin, :cache, :sessions],
|
||||
measurement: :hit_rate
|
||||
),
|
||||
last_value(
|
||||
metric_prefix ++ [:cache, :sites, :size],
|
||||
event_name: [:prom_ex, :plugin, :cachex, :sites],
|
||||
event_name: [:prom_ex, :plugin, :cache, :sites],
|
||||
measurement: :count
|
||||
),
|
||||
last_value(
|
||||
metric_prefix ++ [:cache, :sites, :hit_ratio],
|
||||
event_name: [:prom_ex, :plugin, :cachex, :sites],
|
||||
event_name: [:prom_ex, :plugin, :cache, :sites],
|
||||
measurement: :hit_rate
|
||||
)
|
||||
]
|
||||
|
4
mix.exs
4
mix.exs
@ -67,7 +67,6 @@ defmodule Plausible.MixProject do
|
||||
{:bamboo_mua, "~> 0.1.4"},
|
||||
{:bcrypt_elixir, "~> 3.0"},
|
||||
{:bypass, "~> 2.1", only: [:dev, :test, :small_test]},
|
||||
{:cachex, "~> 3.4"},
|
||||
{:ecto_ch, "~> 0.3"},
|
||||
{:cloak, "~> 1.1"},
|
||||
{:cloak_ecto, "~> 1.2"},
|
||||
@ -141,7 +140,8 @@ defmodule Plausible.MixProject do
|
||||
{:ex_aws_s3, "~> 2.5"},
|
||||
{:sweet_xml, "~> 0.7.4"},
|
||||
{:testcontainers, "~> 1.6", only: [:test, :small_test]},
|
||||
{:zstream, "~> 0.6.4"}
|
||||
{:zstream, "~> 0.6.4"},
|
||||
{:con_cache, "~> 1.0"}
|
||||
]
|
||||
end
|
||||
|
||||
|
6
mix.lock
6
mix.lock
@ -8,7 +8,6 @@
|
||||
"bcrypt_elixir": {:hex, :bcrypt_elixir, "3.1.0", "0b110a9a6c619b19a7f73fa3004aa11d6e719a67e672d1633dc36b6b2290a0f7", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2ad2acb5a8bc049e8d5aa267802631912bb80d5f4110a178ae7999e69dca1bf7"},
|
||||
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
|
||||
"bypass": {:hex, :bypass, "2.1.0", "909782781bf8e20ee86a9cabde36b259d44af8b9f38756173e8f5e2e1fabb9b1", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "d9b5df8fa5b7a6efa08384e9bbecfe4ce61c77d28a4282f79e02f1ef78d96b80"},
|
||||
"cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"},
|
||||
"castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"},
|
||||
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
|
||||
"ch": {:hex, :ch, "0.2.5", "b8d70689951bd14c8c8791dc72cdc957ba489ceae723e79cf1a91d95b6b855ae", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: false]}], "hexpm", "97de104c8f513a23c6d673da37741f68ae743f6cdb654b96a728d382e2fba4de"},
|
||||
@ -19,6 +18,7 @@
|
||||
"combination": {:hex, :combination, "0.0.3", "746aedca63d833293ec6e835aa1f34974868829b1486b1e1cb0685f0b2ae1f41", [:mix], [], "hexpm", "72b099f463df42ef7dc6371d250c7070b57b6c5902853f69deb894f79eda18ca"},
|
||||
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
|
||||
"comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"},
|
||||
"con_cache": {:hex, :con_cache, "1.0.0", "6405e2bd5d5005334af72939432783562a8c35a196c2e63108fe10bb97b366e6", [:mix], [], "hexpm", "4d1f5cb1a67f3c1a468243dc98d10ac83af7f3e33b7e7c15999dc2c9bc0a551e"},
|
||||
"cors_plug": {:hex, :cors_plug, "3.0.3", "7c3ac52b39624bc616db2e937c282f3f623f25f8d550068b6710e58d04a0e330", [:mix], [{:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3f2d759e8c272ed3835fab2ef11b46bddab8c1ab9528167bd463b6452edf830d"},
|
||||
"cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
|
||||
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
|
||||
@ -41,7 +41,6 @@
|
||||
"eqrcode": {:hex, :eqrcode, "0.1.10", "6294fece9d68ad64eef1c3c92cf111cfd6469f4fbf230a2d4cc905a682178f3f", [:mix], [], "hexpm", "da30e373c36a0fd37ab6f58664b16029919896d6c45a68a95cc4d713e81076f1"},
|
||||
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
|
||||
"esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
|
||||
"eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
|
||||
"ex_aws": {:hex, :ex_aws, "2.5.1", "7418917974ea42e9e84b25e88b9f3d21a861d5f953ad453e212f48e593d8d39f", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1b95431f70c446fa1871f0eb9b183043c5a625f75f9948a42d25f43ae2eff12b"},
|
||||
"ex_aws_s3": {:hex, :ex_aws_s3, "2.5.3", "422468e5c3e1a4da5298e66c3468b465cfd354b842e512cb1f6fbbe4e2f5bdaf", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "4f09dd372cc386550e484808c5ac5027766c8d0cd8271ccc578b82ee6ef4f3b8"},
|
||||
"ex_cldr": {:hex, :ex_cldr, "2.37.5", "9da6d97334035b961d2c2de167dc6af8cd3e09859301a5b8f49f90bd8b034593", [:mix], [{:cldr_utils, "~> 2.21", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "74ad5ddff791112ce4156382e171a5f5d3766af9d5c4675e0571f081fe136479"},
|
||||
@ -73,7 +72,6 @@
|
||||
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
|
||||
"joken": {:hex, :joken, "2.6.0", "b9dd9b6d52e3e6fcb6c65e151ad38bf4bc286382b5b6f97079c47ade6b1bcc6a", [:mix], [{:jose, "~> 1.11.5", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "5a95b05a71cd0b54abd35378aeb1d487a23a52c324fa7efdffc512b655b5aaa7"},
|
||||
"jose": {:hex, :jose, "1.11.6", "613fda82552128aa6fb804682e3a616f4bc15565a048dabd05b1ebd5827ed965", [:mix, :rebar3], [], "hexpm", "6275cb75504f9c1e60eeacb771adfeee4905a9e182103aa59b53fed651ff9738"},
|
||||
"jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},
|
||||
"kaffy": {:hex, :kaffy, "0.10.2", "72e807c525323bd0cbc3ac0c127b7bde61caffdc576fb6554964d3fe6a2a6100", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0.2", [hex: :phoenix_view, repo: "hexpm", optional: false]}], "hexpm", "651cad5f3bcc91510a671c13c7a273b8b8195fdf2d809208708baecbb77300bf"},
|
||||
"location": {:git, "https://github.com/plausible/location.git", "3f360af0c9deac1d2ca0bd1c4fcb8769b673d948", []},
|
||||
"locus": {:hex, :locus, "2.3.6", "c9f53fd5df872fca66a54dc0aa2f8b2d3640388e56a0c39a741be0df6d8854bf", [:rebar3], [{:tls_certificate_check, "~> 1.9", [hex: :tls_certificate_check, repo: "hexpm", optional: false]}], "hexpm", "6087aa9a69673e7011837fb4b3d7f756560adde76892c32f5f93904ee30064e2"},
|
||||
@ -135,7 +133,6 @@
|
||||
"scrivener_ecto": {:hex, :scrivener_ecto, "2.7.0", "cf64b8cb8a96cd131cdbcecf64e7fd395e21aaa1cb0236c42a7c2e34b0dca580", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm", "e809f171687806b0031129034352f5ae44849720c48dd839200adeaf0ac3e260"},
|
||||
"sentry": {:hex, :sentry, "8.1.0", "8d235b62fce5f8e067ea1644e30939405b71a5e1599d9529ff82899d11d03f2b", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, "~> 2.3", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "f9fc7641ef61e885510f5e5963c2948b9de1de597c63f781e9d3d6c9c8681ab4"},
|
||||
"siphash": {:hex, :siphash, "3.2.0", "ec03fd4066259218c85e2a4b8eec4bb9663bc02b127ea8a0836db376ba73f2ed", [:make, :mix], [], "hexpm", "ba3810701c6e95637a745e186e8a4899087c3b079ba88fb8f33df054c3b0b7c3"},
|
||||
"sleeplocks": {:hex, :sleeplocks, "1.1.2", "d45aa1c5513da48c888715e3381211c859af34bee9b8290490e10c90bb6ff0ca", [:rebar3], [], "hexpm", "9fe5d048c5b781d6305c1a3a0f40bb3dfc06f49bf40571f3d2d0c57eaa7f59a5"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
|
||||
"sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"},
|
||||
"tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"},
|
||||
@ -151,7 +148,6 @@
|
||||
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
|
||||
"ua_inspector": {:hex, :ua_inspector, "3.8.0", "c0b0d13200a9bd509225f15ea8cf275c0bec27390a21c355746ff8b8a88c3e4d", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:yamerl, "~> 0.7", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "7c980bae82a4754075b933e0f383935a681e5a2628856ad3ecf6eb80d8139539"},
|
||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
||||
"unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"},
|
||||
"uuid": {:hex, :uuid, "1.1.8", "e22fc04499de0de3ed1116b770c7737779f226ceefa0badb3592e64d5cfb4eb9", [:mix], [], "hexpm", "c790593b4c3b601f5dc2378baae7efaf5b3d73c4c6456ba85759905be792f2ac"},
|
||||
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
||||
"websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"},
|
||||
|
45
test/plausible/cache/stats_test.exs
vendored
Normal file
45
test/plausible/cache/stats_test.exs
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
defmodule Plausible.Cache.StatsTest do
|
||||
use Plausible.DataCase, async: true
|
||||
|
||||
alias Plausible.Cache.Stats
|
||||
|
||||
test "when tracking is not initialized, stats are 0" do
|
||||
assert {:ok, %{hit_rate: +0.0, count: 0}} = Stats.gather(:foo)
|
||||
end
|
||||
|
||||
test "when cache is started, stats are 0", %{test: test} do
|
||||
assert {:ok, %{hit_rate: +0.0, count: 0}} = Stats.gather(test)
|
||||
end
|
||||
|
||||
test "tracking changes hit ratio", %{test: test} do
|
||||
Stats.record_miss(test)
|
||||
assert {:ok, %{hit_rate: +0.0, count: 0}} = Stats.gather(test)
|
||||
|
||||
Stats.record_hit(test)
|
||||
assert {:ok, %{hit_rate: 50.0, count: 0}} = Stats.gather(test)
|
||||
|
||||
Stats.record_hit(test)
|
||||
Stats.record_hit(test)
|
||||
assert {:ok, %{hit_rate: 75.0, count: 0}} = Stats.gather(test)
|
||||
|
||||
Stats.record_miss(test)
|
||||
Stats.record_miss(test)
|
||||
assert {:ok, %{hit_rate: 50.0, count: 0}} = Stats.gather(test)
|
||||
end
|
||||
|
||||
test "hit ratio goes up to 100", %{test: test} do
|
||||
Stats.record_hit(test)
|
||||
Stats.record_hit(test)
|
||||
Stats.record_hit(test)
|
||||
assert {:ok, %{hit_rate: 100.0, count: 0}} = Stats.gather(test)
|
||||
end
|
||||
|
||||
test "count comes from cache adapter", %{test: test} do
|
||||
%{start: {m, f, a}} = Plausible.Cache.Adapter.child_spec(test, test)
|
||||
{:ok, _} = apply(m, f, a)
|
||||
|
||||
Plausible.Cache.Adapter.put(test, :key, :value)
|
||||
assert Stats.size(test) == 1
|
||||
assert {:ok, %{hit_rate: +0.0, count: 1}} = Stats.gather(test)
|
||||
end
|
||||
end
|
@ -50,7 +50,7 @@ defmodule Plausible.CacheTest do
|
||||
assert ExampleCache.get("key", force?: true, cache_name: NonExistingCache) == nil
|
||||
end)
|
||||
|
||||
assert log =~ "Error retrieving key from 'NonExistingCache': :no_cache"
|
||||
assert log =~ "Error retrieving key from 'NonExistingCache'"
|
||||
end
|
||||
|
||||
test "cache is not ready when it doesn't exist", %{test: test} do
|
||||
@ -58,6 +58,47 @@ defmodule Plausible.CacheTest do
|
||||
end
|
||||
end
|
||||
|
||||
describe "stats tracking" do
|
||||
test "get affects hit rate", %{test: test} do
|
||||
{:ok, _} = start_test_cache(test)
|
||||
:ok = ExampleCache.merge_items([{"item1", :item1}], cache_name: test)
|
||||
assert ExampleCache.get("item1", cache_name: test, force?: true)
|
||||
assert {:ok, %{hit_rate: 100.0}} = Plausible.Cache.Stats.gather(test)
|
||||
refute ExampleCache.get("item2", cache_name: test, force?: true)
|
||||
assert {:ok, %{hit_rate: 50.0}} = Plausible.Cache.Stats.gather(test)
|
||||
end
|
||||
|
||||
test "get_or_store affects hit rate", %{test: test} do
|
||||
{:ok, _} = start_test_cache(test)
|
||||
|
||||
:ok = ExampleCache.merge_items([{"item1", :item1}], cache_name: test)
|
||||
assert ExampleCache.get("item1", cache_name: test, force?: true)
|
||||
|
||||
# first read of item2 is evaluated from a function and stored
|
||||
assert "value" ==
|
||||
ExampleCache.get_or_store("item2", fn -> "value" end,
|
||||
cache_name: test,
|
||||
force?: true
|
||||
)
|
||||
|
||||
# subsequent gets are read from cache and the function is disregarded
|
||||
assert "value" ==
|
||||
ExampleCache.get_or_store("item2", fn -> "disregard" end,
|
||||
cache_name: test,
|
||||
force?: true
|
||||
)
|
||||
|
||||
assert "value" ==
|
||||
ExampleCache.get_or_store("item2", fn -> "disregard" end,
|
||||
cache_name: test,
|
||||
force?: true
|
||||
)
|
||||
|
||||
# 3 hits, 1 miss
|
||||
assert {:ok, %{hit_rate: 75.0}} = Plausible.Cache.Stats.gather(test)
|
||||
end
|
||||
end
|
||||
|
||||
describe "merging cache items" do
|
||||
test "merging adds new items", %{test: test} do
|
||||
{:ok, _} = start_test_cache(test)
|
||||
|
@ -323,7 +323,6 @@ defmodule Plausible.Site.CacheTest do
|
||||
@items1 for i <- 1..200_000, do: {i, nil, :batch1}
|
||||
@items2 for _ <- 1..200_000, do: {Enum.random(1..400_000), nil, :batch2}
|
||||
@max_seconds 2
|
||||
@tag :slow
|
||||
test "merging large sets is expected to be under #{@max_seconds} seconds", %{test: test} do
|
||||
{:ok, _} = start_test_cache(test)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user