Cachex: Make caching provider switchable at runtime.

Defaults to Cachex.
This commit is contained in:
lain 2020-12-18 17:44:46 +01:00
parent 9a744d49c8
commit 713612c377
20 changed files with 92 additions and 59 deletions

View file

@ -24,6 +24,8 @@ defmodule Pleroma.Activity do
@primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true} @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
schema "activities" do schema "activities" do
field(:data, :map) field(:data, :map)
field(:local, :boolean, default: true) field(:local, :boolean, default: true)
@ -298,7 +300,7 @@ def delete_all_by_object_ap_id(_), do: nil
defp purge_web_resp_cache(%Activity{} = activity) do defp purge_web_resp_cache(%Activity{} = activity) do
%{path: path} = URI.parse(activity.data["id"]) %{path: path} = URI.parse(activity.data["id"])
Cachex.del(:web_resp_cache, path) @cachex.del(:web_resp_cache, path)
activity activity
end end

View file

@ -7,6 +7,8 @@ defmodule Pleroma.Captcha do
alias Plug.Crypto.KeyGenerator alias Plug.Crypto.KeyGenerator
alias Plug.Crypto.MessageEncryptor alias Plug.Crypto.MessageEncryptor
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
@doc """ @doc """
Ask the configured captcha service for a new captcha Ask the configured captcha service for a new captcha
""" """
@ -86,7 +88,7 @@ defp validate_expiration(created_at) do
end end
defp validate_usage(token) do defp validate_usage(token) do
if is_nil(Cachex.get!(:used_captcha_cache, token)) do if is_nil(@cachex.get!(:used_captcha_cache, token)) do
:ok :ok
else else
{:error, :already_used} {:error, :already_used}
@ -95,7 +97,7 @@ defp validate_usage(token) do
defp mark_captcha_as_used(token) do defp mark_captcha_as_used(token) do
ttl = seconds_valid() |> :timer.seconds() ttl = seconds_valid() |> :timer.seconds()
Cachex.put(:used_captcha_cache, token, true, ttl: ttl) @cachex.put(:used_captcha_cache, token, true, ttl: ttl)
end end
defp method, do: Pleroma.Config.get!([__MODULE__, :method]) defp method, do: Pleroma.Config.get!([__MODULE__, :method])

View file

@ -20,6 +20,8 @@ defmodule Pleroma.Emoji.Pack do
name: String.t() name: String.t()
} }
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
alias Pleroma.Emoji alias Pleroma.Emoji
alias Pleroma.Emoji.Pack alias Pleroma.Emoji.Pack
alias Pleroma.Utils alias Pleroma.Utils
@ -415,7 +417,7 @@ defp create_archive_and_cache(pack, hash) do
ttl_per_file = Pleroma.Config.get!([:emoji, :shared_pack_cache_seconds_per_file]) ttl_per_file = Pleroma.Config.get!([:emoji, :shared_pack_cache_seconds_per_file])
overall_ttl = :timer.seconds(ttl_per_file * Enum.count(files)) overall_ttl = :timer.seconds(ttl_per_file * Enum.count(files))
Cachex.put!( @cachex.put!(
:emoji_packs_cache, :emoji_packs_cache,
pack.name, pack.name,
# if pack.json MD5 changes, the cache is not valid anymore # if pack.json MD5 changes, the cache is not valid anymore
@ -618,7 +620,7 @@ defp download_archive(url, sha) do
defp fetch_archive(pack) do defp fetch_archive(pack) do
hash = :crypto.hash(:md5, File.read!(pack.pack_file)) hash = :crypto.hash(:md5, File.read!(pack.pack_file))
case Cachex.get!(:emoji_packs_cache, pack.name) do case @cachex.get!(:emoji_packs_cache, pack.name) do
%{hash: ^hash, pack_data: archive} -> archive %{hash: ^hash, pack_data: archive} -> archive
_ -> create_archive_and_cache(pack, hash) _ -> create_archive_and_cache(pack, hash)
end end

View file

@ -6,6 +6,8 @@ defmodule Pleroma.HTML do
# Scrubbers are compiled on boot so they can be configured in OTP releases # Scrubbers are compiled on boot so they can be configured in OTP releases
# @on_load :compile_scrubbers # @on_load :compile_scrubbers
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def compile_scrubbers do def compile_scrubbers do
dir = Path.join(:code.priv_dir(:pleroma), "scrubbers") dir = Path.join(:code.priv_dir(:pleroma), "scrubbers")
@ -56,7 +58,7 @@ def get_cached_scrubbed_html_for_activity(
) do ) do
key = "#{key}#{generate_scrubber_signature(scrubbers)}|#{activity.id}" key = "#{key}#{generate_scrubber_signature(scrubbers)}|#{activity.id}"
Cachex.fetch!(:scrubber_cache, key, fn _key -> @cachex.fetch!(:scrubber_cache, key, fn _key ->
object = Pleroma.Object.normalize(activity) object = Pleroma.Object.normalize(activity)
ensure_scrubbed_html(content, scrubbers, object.data["fake"] || false, callback) ensure_scrubbed_html(content, scrubbers, object.data["fake"] || false, callback)
end) end)
@ -105,7 +107,7 @@ def extract_first_external_url_from_object(%{data: %{"content" => content}} = ob
unless object.data["fake"] do unless object.data["fake"] do
key = "URL|#{object.id}" key = "URL|#{object.id}"
Cachex.fetch!(:scrubber_cache, key, fn _key -> @cachex.fetch!(:scrubber_cache, key, fn _key ->
{:commit, {:ok, extract_first_external_url(content)}} {:commit, {:ok, extract_first_external_url(content)}}
end) end)
else else

View file

@ -23,6 +23,8 @@ defmodule Pleroma.Object do
@derive {Jason.Encoder, only: [:data]} @derive {Jason.Encoder, only: [:data]}
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
schema "objects" do schema "objects" do
field(:data, :map) field(:data, :map)
@ -156,9 +158,9 @@ def authorize_access(%Object{}, %User{}), do: :ok
def get_cached_by_ap_id(ap_id) do def get_cached_by_ap_id(ap_id) do
key = "object:#{ap_id}" key = "object:#{ap_id}"
with {:ok, nil} <- Cachex.get(:object_cache, key), with {:ok, nil} <- @cachex.get(:object_cache, key),
object when not is_nil(object) <- get_by_ap_id(ap_id), object when not is_nil(object) <- get_by_ap_id(ap_id),
{:ok, true} <- Cachex.put(:object_cache, key, object) do {:ok, true} <- @cachex.put(:object_cache, key, object) do
object object
else else
{:ok, object} -> object {:ok, object} -> object
@ -216,13 +218,13 @@ def prune(%Object{data: %{"id" => _id}} = object) do
end end
def invalid_object_cache(%Object{data: %{"id" => id}}) do def invalid_object_cache(%Object{data: %{"id" => id}}) do
with {:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do with {:ok, true} <- @cachex.del(:object_cache, "object:#{id}") do
Cachex.del(:web_resp_cache, URI.parse(id).path) @cachex.del(:web_resp_cache, URI.parse(id).path)
end end
end end
def set_cache(%Object{data: %{"id" => ap_id}} = object) do def set_cache(%Object{data: %{"id" => ap_id}} = object) do
Cachex.put(:object_cache, "object:#{ap_id}", object) @cachex.put(:object_cache, "object:#{ap_id}", object)
{:ok, object} {:ok, object}
end end

View file

@ -17,6 +17,8 @@ defmodule Pleroma.ReverseProxy do
@failed_request_ttl :timer.seconds(60) @failed_request_ttl :timer.seconds(60)
@methods ~w(GET HEAD) @methods ~w(GET HEAD)
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def max_read_duration_default, do: @max_read_duration def max_read_duration_default, do: @max_read_duration
def default_cache_control_header, do: @default_cache_control_header def default_cache_control_header, do: @default_cache_control_header
@ -107,7 +109,7 @@ def call(conn = %{method: method}, url, opts) when method in @methods do
opts opts
end end
with {:ok, nil} <- Cachex.get(:failed_proxy_url_cache, url), with {:ok, nil} <- @cachex.get(:failed_proxy_url_cache, url),
{:ok, code, headers, client} <- request(method, url, req_headers, client_opts), {:ok, code, headers, client} <- request(method, url, req_headers, client_opts),
:ok <- :ok <-
header_length_constraint( header_length_constraint(
@ -427,6 +429,6 @@ defp track_failed_url(url, error, opts) do
nil nil
end end
Cachex.put(:failed_proxy_url_cache, url, true, ttl: ttl) @cachex.put(:failed_proxy_url_cache, url, true, ttl: ttl)
end end
end end

View file

@ -81,6 +81,8 @@ defmodule Pleroma.User do
] ]
] ]
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
schema "users" do schema "users" do
field(:bio, :string, default: "") field(:bio, :string, default: "")
field(:raw_bio, :string) field(:raw_bio, :string)
@ -246,13 +248,13 @@ def unquote(:"#{outgoing_relation_target}_ap_ids")(user, restrict_deactivated? \
end end
def cached_blocked_users_ap_ids(user) do def cached_blocked_users_ap_ids(user) do
Cachex.fetch!(:user_cache, "blocked_users_ap_ids:#{user.ap_id}", fn _ -> @cachex.fetch!(:user_cache, "blocked_users_ap_ids:#{user.ap_id}", fn _ ->
blocked_users_ap_ids(user) blocked_users_ap_ids(user)
end) end)
end end
def cached_muted_users_ap_ids(user) do def cached_muted_users_ap_ids(user) do
Cachex.fetch!(:user_cache, "muted_users_ap_ids:#{user.ap_id}", fn _ -> @cachex.fetch!(:user_cache, "muted_users_ap_ids:#{user.ap_id}", fn _ ->
muted_users_ap_ids(user) muted_users_ap_ids(user)
end) end)
end end
@ -1016,9 +1018,9 @@ def set_cache({:ok, user}), do: set_cache(user)
def set_cache({:error, err}), do: {:error, err} def set_cache({:error, err}), do: {:error, err}
def set_cache(%User{} = user) do def set_cache(%User{} = user) do
Cachex.put(:user_cache, "ap_id:#{user.ap_id}", user) @cachex.put(:user_cache, "ap_id:#{user.ap_id}", user)
Cachex.put(:user_cache, "nickname:#{user.nickname}", user) @cachex.put(:user_cache, "nickname:#{user.nickname}", user)
Cachex.put(:user_cache, "friends_ap_ids:#{user.nickname}", get_user_friends_ap_ids(user)) @cachex.put(:user_cache, "friends_ap_ids:#{user.nickname}", get_user_friends_ap_ids(user))
{:ok, user} {:ok, user}
end end
@ -1041,26 +1043,26 @@ def get_user_friends_ap_ids(user) do
@spec get_cached_user_friends_ap_ids(User.t()) :: [String.t()] @spec get_cached_user_friends_ap_ids(User.t()) :: [String.t()]
def get_cached_user_friends_ap_ids(user) do def get_cached_user_friends_ap_ids(user) do
Cachex.fetch!(:user_cache, "friends_ap_ids:#{user.ap_id}", fn _ -> @cachex.fetch!(:user_cache, "friends_ap_ids:#{user.ap_id}", fn _ ->
get_user_friends_ap_ids(user) get_user_friends_ap_ids(user)
end) end)
end end
def invalidate_cache(user) do def invalidate_cache(user) do
Cachex.del(:user_cache, "ap_id:#{user.ap_id}") @cachex.del(:user_cache, "ap_id:#{user.ap_id}")
Cachex.del(:user_cache, "nickname:#{user.nickname}") @cachex.del(:user_cache, "nickname:#{user.nickname}")
Cachex.del(:user_cache, "friends_ap_ids:#{user.ap_id}") @cachex.del(:user_cache, "friends_ap_ids:#{user.ap_id}")
Cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}") @cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}")
Cachex.del(:user_cache, "muted_users_ap_ids:#{user.ap_id}") @cachex.del(:user_cache, "muted_users_ap_ids:#{user.ap_id}")
end end
@spec get_cached_by_ap_id(String.t()) :: User.t() | nil @spec get_cached_by_ap_id(String.t()) :: User.t() | nil
def get_cached_by_ap_id(ap_id) do def get_cached_by_ap_id(ap_id) do
key = "ap_id:#{ap_id}" key = "ap_id:#{ap_id}"
with {:ok, nil} <- Cachex.get(:user_cache, key), with {:ok, nil} <- @cachex.get(:user_cache, key),
user when not is_nil(user) <- get_by_ap_id(ap_id), user when not is_nil(user) <- get_by_ap_id(ap_id),
{:ok, true} <- Cachex.put(:user_cache, key, user) do {:ok, true} <- @cachex.put(:user_cache, key, user) do
user user
else else
{:ok, user} -> user {:ok, user} -> user
@ -1072,11 +1074,11 @@ def get_cached_by_id(id) do
key = "id:#{id}" key = "id:#{id}"
ap_id = ap_id =
Cachex.fetch!(:user_cache, key, fn _ -> @cachex.fetch!(:user_cache, key, fn _ ->
user = get_by_id(id) user = get_by_id(id)
if user do if user do
Cachex.put(:user_cache, "ap_id:#{user.ap_id}", user) @cachex.put(:user_cache, "ap_id:#{user.ap_id}", user)
{:commit, user.ap_id} {:commit, user.ap_id}
else else
{:ignore, ""} {:ignore, ""}
@ -1089,7 +1091,7 @@ def get_cached_by_id(id) do
def get_cached_by_nickname(nickname) do def get_cached_by_nickname(nickname) do
key = "nickname:#{nickname}" key = "nickname:#{nickname}"
Cachex.fetch!(:user_cache, key, fn -> @cachex.fetch!(:user_cache, key, fn ->
case get_or_fetch_by_nickname(nickname) do case get_or_fetch_by_nickname(nickname) do
{:ok, user} -> {:commit, user} {:ok, user} -> {:commit, user}
{:error, _error} -> {:ignore, nil} {:error, _error} -> {:ignore, nil}
@ -1358,7 +1360,7 @@ def mute(%User{} = muter, %User{} = mutee, params \\ %{}) do
) )
end end
Cachex.del(:user_cache, "muted_users_ap_ids:#{muter.ap_id}") @cachex.del(:user_cache, "muted_users_ap_ids:#{muter.ap_id}")
{:ok, Enum.filter([user_mute, user_notification_mute], & &1)} {:ok, Enum.filter([user_mute, user_notification_mute], & &1)}
end end
@ -1368,7 +1370,7 @@ def unmute(%User{} = muter, %User{} = mutee) do
with {:ok, user_mute} <- UserRelationship.delete_mute(muter, mutee), with {:ok, user_mute} <- UserRelationship.delete_mute(muter, mutee),
{:ok, user_notification_mute} <- {:ok, user_notification_mute} <-
UserRelationship.delete_notification_mute(muter, mutee) do UserRelationship.delete_notification_mute(muter, mutee) do
Cachex.del(:user_cache, "muted_users_ap_ids:#{muter.ap_id}") @cachex.del(:user_cache, "muted_users_ap_ids:#{muter.ap_id}")
{:ok, [user_mute, user_notification_mute]} {:ok, [user_mute, user_notification_mute]}
end end
end end
@ -2365,7 +2367,7 @@ def unblock_domain(user, domain_blocked) do
{:ok, UserRelationship.t()} | {:error, Ecto.Changeset.t()} {:ok, UserRelationship.t()} | {:error, Ecto.Changeset.t()}
defp add_to_block(%User{} = user, %User{} = blocked) do defp add_to_block(%User{} = user, %User{} = blocked) do
with {:ok, relationship} <- UserRelationship.create_block(user, blocked) do with {:ok, relationship} <- UserRelationship.create_block(user, blocked) do
Cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}") @cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}")
{:ok, relationship} {:ok, relationship}
end end
end end
@ -2374,7 +2376,7 @@ defp add_to_block(%User{} = user, %User{} = blocked) do
{:ok, UserRelationship.t()} | {:ok, nil} | {:error, Ecto.Changeset.t()} {:ok, UserRelationship.t()} | {:ok, nil} | {:error, Ecto.Changeset.t()}
defp remove_from_block(%User{} = user, %User{} = blocked) do defp remove_from_block(%User{} = user, %User{} = blocked) do
with {:ok, relationship} <- UserRelationship.delete_block(user, blocked) do with {:ok, relationship} <- UserRelationship.delete_block(user, blocked) do
Cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}") @cachex.del(:user_cache, "blocked_users_ap_ids:#{user.ap_id}")
{:ok, relationship} {:ok, relationship}
end end
end end

View file

@ -27,6 +27,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
require Logger require Logger
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def handle(object, meta \\ []) def handle(object, meta \\ [])
# Task this handles # Task this handles
@ -312,7 +314,7 @@ def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do
{:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id) {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
{:ok, cm_ref} = MessageReference.create(chat, object, user.ap_id != actor.ap_id) {:ok, cm_ref} = MessageReference.create(chat, object, user.ap_id != actor.ap_id)
Cachex.put( @cachex.put(
:chat_message_id_idempotency_key_cache, :chat_message_id_idempotency_key_cache,
cm_ref.id, cm_ref.id,
meta[:idempotency_key] meta[:idempotency_key]

View file

@ -9,6 +9,8 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheController do
alias Pleroma.Web.MediaProxy alias Pleroma.Web.MediaProxy
alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.Plugs.OAuthScopesPlug
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
plug(Pleroma.Web.ApiSpec.CastAndValidate) plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug( plug(
@ -38,7 +40,7 @@ def index(%{assigns: %{user: _}} = conn, params) do
defp fetch_entries(params) do defp fetch_entries(params) do
MediaProxy.cache_table() MediaProxy.cache_table()
|> Cachex.stream!(Cachex.Query.create(true, :key)) |> @cachex.stream!(@cachex.Query.create(true, :key))
|> filter_entries(params[:query]) |> filter_entries(params[:query])
end end

View file

@ -26,6 +26,8 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PollOperation defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PollOperation
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
@doc "GET /api/v1/polls/:id" @doc "GET /api/v1/polls/:id"
def show(%{assigns: %{user: user}} = conn, %{id: id}) do def show(%{assigns: %{user: user}} = conn, %{id: id}) do
with %Object{} = object <- Object.get_by_id_and_maybe_refetch(id, interval: 60), with %Object{} = object <- Object.get_by_id_and_maybe_refetch(id, interval: 60),
@ -55,7 +57,7 @@ def vote(%{assigns: %{user: user}, body_params: %{choices: choices}} = conn, %{i
defp get_cached_vote_or_vote(user, object, choices) do defp get_cached_vote_or_vote(user, object, choices) do
idempotency_key = "polls:#{user.id}:#{object.data["id"]}" idempotency_key = "polls:#{user.id}:#{object.data["id"]}"
Cachex.fetch!(:idempotency_cache, idempotency_key, fn -> @cachex.fetch!(:idempotency_cache, idempotency_key, fn ->
case CommonAPI.vote(user, object, choices) do case CommonAPI.vote(user, object, choices) do
{:error, _message} = res -> {:ignore, res} {:error, _message} = res -> {:ignore, res}
res -> {:commit, res} res -> {:commit, res}

View file

@ -12,29 +12,31 @@ defmodule Pleroma.Web.MediaProxy do
@base64_opts [padding: false] @base64_opts [padding: false]
@cache_table :banned_urls_cache @cache_table :banned_urls_cache
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def cache_table, do: @cache_table def cache_table, do: @cache_table
@spec in_banned_urls(String.t()) :: boolean() @spec in_banned_urls(String.t()) :: boolean()
def in_banned_urls(url), do: elem(Cachex.exists?(@cache_table, url(url)), 1) def in_banned_urls(url), do: elem(@cachex.exists?(@cache_table, url(url)), 1)
def remove_from_banned_urls(urls) when is_list(urls) do def remove_from_banned_urls(urls) when is_list(urls) do
Cachex.execute!(@cache_table, fn cache -> @cachex.execute!(@cache_table, fn cache ->
Enum.each(Invalidation.prepare_urls(urls), &Cachex.del(cache, &1)) Enum.each(Invalidation.prepare_urls(urls), &@cachex.del(cache, &1))
end) end)
end end
def remove_from_banned_urls(url) when is_binary(url) do def remove_from_banned_urls(url) when is_binary(url) do
Cachex.del(@cache_table, url(url)) @cachex.del(@cache_table, url(url))
end end
def put_in_banned_urls(urls) when is_list(urls) do def put_in_banned_urls(urls) when is_list(urls) do
Cachex.execute!(@cache_table, fn cache -> @cachex.execute!(@cache_table, fn cache ->
Enum.each(Invalidation.prepare_urls(urls), &Cachex.put(cache, &1, true)) Enum.each(Invalidation.prepare_urls(urls), &@cachex.put(cache, &1, true))
end) end)
end end
def put_in_banned_urls(url) when is_binary(url) do def put_in_banned_urls(url) when is_binary(url) do
Cachex.put(@cache_table, url(url), true) @cachex.put(@cache_table, url(url), true)
end end
def url(url) when is_nil(url) or url == "", do: nil def url(url) when is_nil(url) or url == "", do: nil

View file

@ -10,6 +10,8 @@ defmodule Pleroma.Web.PleromaAPI.Chat.MessageReferenceView do
alias Pleroma.Web.CommonAPI.Utils alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MastodonAPI.StatusView
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def render( def render(
"show.json", "show.json",
%{ %{
@ -51,7 +53,7 @@ def render("index.json", opts) do
end end
defp put_idempotency_key(data) do defp put_idempotency_key(data) do
with {:ok, idempotency_key} <- Cachex.get(:chat_message_id_idempotency_key_cache, data.id) do with {:ok, idempotency_key} <- @cachex.get(:chat_message_id_idempotency_key_cache, data.id) do
data data
|> Maps.put_if_present(:idempotency_key, idempotency_key) |> Maps.put_if_present(:idempotency_key, idempotency_key)
else else

View file

@ -41,6 +41,8 @@ def index(conn, _params) do
@defaults %{ttl: nil, query_params: true} @defaults %{ttl: nil, query_params: true}
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
@impl true @impl true
def init([]), do: @defaults def init([]), do: @defaults
@ -53,7 +55,7 @@ def init(opts) do
def call(%{method: "GET"} = conn, opts) do def call(%{method: "GET"} = conn, opts) do
key = cache_key(conn, opts) key = cache_key(conn, opts)
case Cachex.get(:web_resp_cache, key) do case @cachex.get(:web_resp_cache, key) do
{:ok, nil} -> {:ok, nil} ->
cache_resp(conn, opts) cache_resp(conn, opts)
@ -97,11 +99,11 @@ defp cache_resp(conn, opts) do
conn = conn =
unless opts[:tracking_fun] do unless opts[:tracking_fun] do
Cachex.put(:web_resp_cache, key, {content_type, body}, ttl: ttl) @cachex.put(:web_resp_cache, key, {content_type, body}, ttl: ttl)
conn conn
else else
tracking_fun_data = Map.get(conn.assigns, :tracking_fun_data, nil) tracking_fun_data = Map.get(conn.assigns, :tracking_fun_data, nil)
Cachex.put(:web_resp_cache, key, {content_type, body, tracking_fun_data}, ttl: ttl) @cachex.put(:web_resp_cache, key, {content_type, body, tracking_fun_data}, ttl: ttl)
opts.tracking_fun.(conn, tracking_fun_data) opts.tracking_fun.(conn, tracking_fun_data)
end end

View file

@ -8,6 +8,8 @@ defmodule Pleroma.Web.Plugs.IdempotencyPlug do
@behaviour Plug @behaviour Plug
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
@impl true @impl true
def init(opts), do: opts def init(opts), do: opts
@ -25,7 +27,7 @@ def call(%{method: method} = conn, _) when method in ["POST", "PUT", "PATCH"] do
def call(conn, _), do: conn def call(conn, _), do: conn
def process_request(conn, key) do def process_request(conn, key) do
case Cachex.get(:idempotency_cache, key) do case @cachex.get(:idempotency_cache, key) do
{:ok, nil} -> {:ok, nil} ->
cache_resposnse(conn, key) cache_resposnse(conn, key)
@ -43,7 +45,7 @@ defp cache_resposnse(conn, key) do
content_type = get_content_type(conn) content_type = get_content_type(conn)
record = {request_id, content_type, conn.status, conn.resp_body} record = {request_id, content_type, conn.status, conn.resp_body}
{:ok, _} = Cachex.put(:idempotency_cache, key, record) {:ok, _} = @cachex.put(:idempotency_cache, key, record)
conn conn
|> put_resp_header("idempotency-key", key) |> put_resp_header("idempotency-key", key)

View file

@ -72,6 +72,8 @@ defmodule Pleroma.Web.Plugs.RateLimiter do
require Logger require Logger
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
@doc false @doc false
def init(plug_opts) do def init(plug_opts) do
plug_opts plug_opts
@ -124,7 +126,7 @@ def inspect_bucket(conn, bucket_name_root, plug_opts) do
key_name = make_key_name(action_settings) key_name = make_key_name(action_settings)
limit = get_limits(action_settings) limit = get_limits(action_settings)
case Cachex.get(bucket_name, key_name) do case @cachex.get(bucket_name, key_name) do
{:error, :no_cache} -> {:error, :no_cache} ->
@inspect_bucket_not_found @inspect_bucket_not_found
@ -157,7 +159,7 @@ defp check_rate(action_settings) do
key_name = make_key_name(action_settings) key_name = make_key_name(action_settings)
limit = get_limits(action_settings) limit = get_limits(action_settings)
case Cachex.get_and_update(bucket_name, key_name, &increment_value(&1, limit)) do case @cachex.get_and_update(bucket_name, key_name, &increment_value(&1, limit)) do
{:commit, value} -> {:commit, value} ->
{:ok, value} {:ok, value}

View file

@ -12,8 +12,9 @@ defmodule Pleroma.Web.RelMe do
if Pleroma.Config.get(:env) == :test do if Pleroma.Config.get(:env) == :test do
def parse(url) when is_binary(url), do: parse_url(url) def parse(url) when is_binary(url), do: parse_url(url)
else else
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def parse(url) when is_binary(url) do def parse(url) when is_binary(url) do
Cachex.fetch!(:rel_me_cache, url, fn _ -> @cachex.fetch!(:rel_me_cache, url, fn _ ->
{:commit, parse_url(url)} {:commit, parse_url(url)}
end) end)
rescue rescue

View file

@ -5,6 +5,8 @@
defmodule Pleroma.Web.RichMedia.Parser do defmodule Pleroma.Web.RichMedia.Parser do
require Logger require Logger
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
defp parsers do defp parsers do
Pleroma.Config.get([:rich_media, :parsers]) Pleroma.Config.get([:rich_media, :parsers])
end end
@ -24,7 +26,7 @@ def parse(url) do
end end
defp get_cached_or_parse(url) do defp get_cached_or_parse(url) do
case Cachex.fetch(:rich_media_cache, url, fn -> case @cachex.fetch(:rich_media_cache, url, fn ->
case parse_url(url) do case parse_url(url) do
{:ok, _} = res -> {:ok, _} = res ->
{:commit, res} {:commit, res}
@ -64,7 +66,7 @@ defp set_error_ttl(_url, {:content_type, _}), do: :ok
defp set_error_ttl(url, _reason) do defp set_error_ttl(url, _reason) do
ttl = Pleroma.Config.get([:rich_media, :failure_backoff], 60_000) ttl = Pleroma.Config.get([:rich_media, :failure_backoff], 60_000)
Cachex.expire(:rich_media_cache, url, ttl) @cachex.expire(:rich_media_cache, url, ttl)
:ok :ok
end end
@ -106,7 +108,7 @@ def set_ttl_based_on_image(data, url) do
{:ok, ttl} when is_number(ttl) -> {:ok, ttl} when is_number(ttl) ->
ttl = ttl * 1000 ttl = ttl * 1000
case Cachex.expire_at(:rich_media_cache, url, ttl) do case @cachex.expire_at(:rich_media_cache, url, ttl) do
{:ok, true} -> {:ok, ttl} {:ok, true} -> {:ok, ttl}
{:ok, false} -> {:error, :no_key} {:ok, false} -> {:error, :no_key}
end end

View file

@ -211,7 +211,7 @@ defp deps do
git: "https://git.pleroma.social/pleroma/elixir-libraries/hackney.git", git: "https://git.pleroma.social/pleroma/elixir-libraries/hackney.git",
ref: "7d7119f0651515d6d7669c78393fd90950a3ec6e", ref: "7d7119f0651515d6d7669c78393fd90950a3ec6e",
override: true}, override: true},
{:mox, "~> 0.5", only: :test}, {:mox, "~> 1.0", only: :test},
{:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test} {:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test}
] ++ oauth_deps() ] ++ oauth_deps()
end end

View file

@ -76,7 +76,7 @@
"mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"}, "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
"mock": {:hex, :mock, "0.3.5", "feb81f52b8dcf0a0d65001d2fec459f6b6a8c22562d94a965862f6cc066b5431", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "6fae404799408300f863550392635d8f7e3da6b71abdd5c393faf41b131c8728"}, "mock": {:hex, :mock, "0.3.5", "feb81f52b8dcf0a0d65001d2fec459f6b6a8c22562d94a965862f6cc066b5431", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "6fae404799408300f863550392635d8f7e3da6b71abdd5c393faf41b131c8728"},
"mogrify": {:hex, :mogrify, "0.7.4", "9b2496dde44b1ce12676f85d7dc531900939e6367bc537c7243a1b089435b32d", [:mix], [], "hexpm", "50d79e337fba6bc95bfbef918058c90f50b17eed9537771e61d4619488f099c3"}, "mogrify": {:hex, :mogrify, "0.7.4", "9b2496dde44b1ce12676f85d7dc531900939e6367bc537c7243a1b089435b32d", [:mix], [], "hexpm", "50d79e337fba6bc95bfbef918058c90f50b17eed9537771e61d4619488f099c3"},
"mox": {:hex, :mox, "0.5.2", "55a0a5ba9ccc671518d068c8dddd20eeb436909ea79d1799e2209df7eaa98b6c", [:mix], [], "hexpm", "df4310628cd628ee181df93f50ddfd07be3e5ecc30232d3b6aadf30bdfe6092b"}, "mox": {:hex, :mox, "1.0.0", "4b3c7005173f47ff30641ba044eb0fe67287743eec9bd9545e37f3002b0a9f8b", [:mix], [], "hexpm", "201b0a20b7abdaaab083e9cf97884950f8a30a1350a1da403b3145e213c6f4df"},
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]}, "myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
"nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"}, "nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"},
"nimble_pool": {:hex, :nimble_pool, "0.1.0", "ffa9d5be27eee2b00b0c634eb649aa27f97b39186fec3c493716c2a33e784ec6", [:mix], [], "hexpm", "343a1eaa620ddcf3430a83f39f2af499fe2370390d4f785cd475b4df5acaf3f9"}, "nimble_pool": {:hex, :nimble_pool, "0.1.0", "ffa9d5be27eee2b00b0c634eb649aa27f97b39186fec3c493716c2a33e784ec6", [:mix], [], "hexpm", "343a1eaa620ddcf3430a83f39f2af499fe2370390d4f785cd475b4df5acaf3f9"},

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: [] os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: []
ExUnit.start(exclude: [:federated | os_exclude]) ExUnit.start(exclude: [:test] ++ [:federated | os_exclude], include: [async: true])
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual) Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)