fix(retention): keep threads whose post a local user quoted
A quote has a context of its own, so the quoted remote thread counted as untouched and was evicted, breaking the local quote. On lain.com 45 of 134 quoted posts went this way. The objects_quote_url index keeps the lookup at one probe per post.
This commit is contained in:
parent
5e425ce9f5
commit
e93f05a79f
5 changed files with 53 additions and 5 deletions
|
|
@ -1 +1 @@
|
|||
Add a bounded retention mode (`config :pleroma, :retention`): a cron worker walks old activities in id order and evicts remote threads nobody local interacted with, in bounded batches, so the database plateaus instead of growing forever. Adds a `retention_cursors` table. `prune_objects --keep-threads` now also keeps threads that are addressed to a local user, still have a notification for one, or contain a reported post.
|
||||
Add a bounded retention mode (`config :pleroma, :retention`): a cron worker walks old activities in id order and evicts remote threads nobody local interacted with, in bounded batches, so the database plateaus instead of growing forever. Adds a `retention_cursors` table. `prune_objects --keep-threads` now also keeps threads that are addressed to a local user, still have a notification for one, contain a post quoted by a local post, or contain a reported post.
|
||||
|
|
|
|||
|
|
@ -1189,10 +1189,7 @@ Control favicons for instances.
|
|||
|
||||
Bounded retention of remote content. Local posts are your data; remote posts are a cache of somebody else's, and this treats them that way. When enabled, a cron worker (`Pleroma.Workers.Cron.RetentionWorker`, hourly by default) evicts a batch of remote threads that nobody local has interacted with and that have been quiet for longer than `remote_post_retention_days` (see [`:instance`](#instance)). The database then plateaus instead of growing without limit.
|
||||
|
||||
A thread is never evicted if it contains a local post, reply, favourite, repeat or reaction, a post bookmarked by a local user, a post addressed to a local user (direct messages and mentions), a post a local user still has a notification for, or a post that was reported. Relationship activities (follows, blocks) and chat messages are never touched. Evicted posts are refetched on demand when somebody opens them again, as with `prune_objects`.
|
||||
|
||||
!!! warning
|
||||
A local quote post does not pin the post it quotes, since quotes do not share the quoted thread's context. Old quoted remote posts can be evicted and will be refetched when the quote is viewed.
|
||||
A thread is never evicted if it contains a local post, reply, favourite, repeat or reaction, a post bookmarked by a local user, a post addressed to a local user (direct messages and mentions), a post quoted by a local post, a post a local user still has a notification for, or a post that was reported. Relationship activities (follows, blocks) and chat messages are never touched. Evicted posts are refetched on demand when somebody opens them again, as with `prune_objects`.
|
||||
|
||||
* `enabled`: Run the worker. Defaults to `false`.
|
||||
* `max_objects`: Optional watermark. When the `objects` table is estimated to hold more rows than this, the oldest unpinned remote threads that have been quiet for more than a day are evicted, whatever `remote_post_retention_days` says. Defaults to `nil` (age only).
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ defmodule Pleroma.Retention do
|
|||
users all carry the thread's context),
|
||||
* is bookmarked by a local user,
|
||||
* is addressed to a local user (direct messages and mentions),
|
||||
* is a post quoted by a local post,
|
||||
* still has a notification for a local user,
|
||||
* is a report (Flag),
|
||||
|
||||
|
|
@ -245,6 +246,18 @@ defmodule Pleroma.Retention do
|
|||
^local_prefix()
|
||||
)
|
||||
)
|
||||
# A local quote has a context of its own, so look up quotes of the posts
|
||||
# here; the objects_quote_url index is on the jsonb value.
|
||||
|> having(
|
||||
[a],
|
||||
not fragment(
|
||||
"bool_or(? ->> 'type' = 'Create' AND EXISTS (SELECT 1 FROM objects q WHERE q.data -> 'quoteUrl' = to_jsonb(associated_object_id(?)) AND left(q.data ->> 'actor', ?) = ?))",
|
||||
a.data,
|
||||
a.data,
|
||||
^local_prefix_length(),
|
||||
^local_prefix()
|
||||
)
|
||||
)
|
||||
|> maybe_keep_non_public(Keyword.get(opts, :keep_non_public, false) == true)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -200,6 +200,29 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do
|
|||
refute Object.get_by_ap_id(old_remote_post2_id)
|
||||
end
|
||||
|
||||
test "with the --keep-threads option it keeps old threads a local user quoted", %{
|
||||
old_insert_date: old_insert_date
|
||||
} do
|
||||
remote_user = insert(:user, local: false)
|
||||
local_user = insert(:user)
|
||||
|
||||
{:ok, quoted} = CommonAPI.post(remote_user, %{status: "quote me"})
|
||||
|
||||
quoted
|
||||
|> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date})
|
||||
|> Repo.update!()
|
||||
|
||||
{:ok, quote} = CommonAPI.post(local_user, %{status: "look", quote_id: quoted.id})
|
||||
|
||||
quote
|
||||
|> Ecto.Changeset.change(%{updated_at: old_insert_date})
|
||||
|> Repo.update!()
|
||||
|
||||
Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-threads"])
|
||||
|
||||
assert Object.get_by_ap_id(quoted.data["object"])
|
||||
end
|
||||
|
||||
test "with the --keep-threads option it keeps old threads addressed to a local user", %{
|
||||
old_insert_date: old_insert_date
|
||||
} do
|
||||
|
|
|
|||
|
|
@ -244,6 +244,21 @@ defmodule Pleroma.RetentionTest do
|
|||
assert Object.get_by_ap_id(post.data["object"])
|
||||
end
|
||||
|
||||
test "keeps an old remote thread whose post a local user quoted", %{old_date: old_date} do
|
||||
remote_user = insert(:user, local: false)
|
||||
local_user = insert(:user)
|
||||
|
||||
quoted = old_remote_post(remote_user, old_date)
|
||||
{:ok, quote} = CommonAPI.post(local_user, %{status: "look at this", quote_id: quoted.id})
|
||||
make_old(quote, old_date)
|
||||
|
||||
# The quote has a context of its own and does not pin the quoted thread.
|
||||
refute quote.data["context"] == quoted.data["context"]
|
||||
|
||||
assert %{contexts: 0} = Retention.run()
|
||||
assert Object.get_by_ap_id(quoted.data["object"])
|
||||
end
|
||||
|
||||
test "keeps an old remote post that was reported", %{old_date: old_date} do
|
||||
remote_user = insert(:user, local: false)
|
||||
local_user = insert(:user)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue