Track usage of media files and add a job to clean them

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2020-11-26 11:41:13 +01:00
parent c19e326bd8
commit c9457fe0d3
78 changed files with 1405 additions and 700 deletions

View File

@@ -0,0 +1,60 @@
defmodule Mobilizon.Service.CleanOrphanMedia do
@moduledoc """
Service to clean orphan media
"""
alias Mobilizon.Actors.Actor
alias Mobilizon.Medias
alias Mobilizon.Medias.Media
alias Mobilizon.Storage.Repo
import Ecto.Query
@grace_period Mobilizon.Config.get([:instance, :orphan_upload_grace_period_hours], 48)
@doc """
Clean orphan media
Remove media that is not attached to an entity, such as media uploads that were never used in entities.
Options:
* `grace_period` how old in hours can the media be before it's taken into account for deletion
* `dry_run` just return the media that would have been deleted, don't actually delete it
"""
@spec clean(Keyword.t()) :: {:ok, list(Media.t())} | {:error, String.t()}
def clean(opts \\ []) do
medias = find_media(opts)
if Keyword.get(opts, :dry_run, false) do
{:ok, medias}
else
Enum.each(medias, fn media ->
Medias.delete_media(media, ignore_file_not_found: true)
end)
{:ok, medias}
end
end
@spec find_media(Keyword.t()) :: list(Media.t())
defp find_media(opts) do
grace_period = Keyword.get(opts, :grace_period, @grace_period)
expiration_date = DateTime.add(DateTime.utc_now(), grace_period * -3600)
Media
|> where([m], m.inserted_at < ^expiration_date)
|> join(:inner, [m], a in Actor)
|> where([_m, a], is_nil(a.domain))
|> join(:left, [m], e in assoc(m, :events))
|> join(:left, [m], ep in assoc(m, :event_picture))
|> join(:left, [m], p in assoc(m, :posts))
|> join(:left, [m], pp in assoc(m, :posts_picture))
|> join(:left, [m], c in assoc(m, :comments))
|> where([_m, _a, e], is_nil(e.id))
|> where([_m, _a, _e, ep], is_nil(ep.id))
|> where([_m, _a, _e, _ep, p], is_nil(p.id))
|> where([_m, _a, _e, _ep, _p, pp], is_nil(pp.id))
|> where([_m, _a, _e, _ep, _p, _pp, c], is_nil(c.id))
|> distinct(true)
|> Repo.all()
end
end

View File

@@ -0,0 +1,31 @@
defmodule Mobilizon.Service.Workers.CleanOrphanMediaWorker do
@moduledoc """
Worker to clean orphan media
"""
use Oban.Worker, queue: "background"
alias Mobilizon.Service.CleanOrphanMedia
@grace_period Mobilizon.Config.get([:instance, :orphan_upload_grace_period_hours], 48)
@impl Oban.Worker
def perform(%Job{}) do
if Mobilizon.Config.get!([:instance, :remove_orphan_uploads]) and should_perform?() do
CleanOrphanMedia.clean()
end
end
@spec should_perform? :: boolean()
defp should_perform? do
case Cachex.get(:key_value, "last_media_cleanup") do
{:ok, %DateTime{} = last_media_cleanup} ->
DateTime.compare(
last_media_cleanup,
DateTime.add(DateTime.utc_now(), @grace_period * -3600)
) == :lt
_ ->
true
end
end
end