commit: cf6587d344d2832dec0768e90e7e8e0a4f292b6c
parent f6c9b003fa53a99d6161c90f3d62a449590b93dc
Author: feld <feld@feld.me>
Date: Fri, 27 Jun 2025 20:25:41 +0000
Merge branch 'delete-instance-improvement' into 'develop'
Queue individual jobs for each user that needs to be deleted when deleting an instance.
See merge request pleroma/pleroma!4377
Diffstat:
6 files changed, 63 insertions(+), 50 deletions(-)
diff --git a/changelog.d/delete-instance.change b/changelog.d/delete-instance.change
@@ -0,0 +1 @@
+Deleting an instance queues individual jobs for each user that needs to be deleted from the server.
diff --git a/lib/pleroma/instances/instance.ex b/lib/pleroma/instances/instance.ex
@@ -9,7 +9,6 @@ defmodule Pleroma.Instances.Instance do
alias Pleroma.Instances.Instance
alias Pleroma.Maps
alias Pleroma.Repo
- alias Pleroma.User
alias Pleroma.Workers.DeleteWorker
use Ecto.Schema
@@ -300,16 +299,4 @@ defmodule Pleroma.Instances.Instance do
DeleteWorker.new(%{"op" => "delete_instance", "host" => host})
|> Oban.insert()
end
-
- def perform(:delete_instance, host) when is_binary(host) do
- User.Query.build(%{nickname: "@#{host}"})
- |> Repo.chunk_stream(100, :batches)
- |> Stream.each(fn users ->
- users
- |> Enum.each(fn user ->
- User.perform(:delete, user)
- end)
- end)
- |> Stream.run()
- end
end
diff --git a/lib/pleroma/workers/delete_worker.ex b/lib/pleroma/workers/delete_worker.ex
@@ -3,7 +3,6 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.DeleteWorker do
- alias Pleroma.Instances.Instance
alias Pleroma.User
use Oban.Worker, queue: :slow
@@ -15,7 +14,15 @@ defmodule Pleroma.Workers.DeleteWorker do
end
def perform(%Job{args: %{"op" => "delete_instance", "host" => host}}) do
- Instance.perform(:delete_instance, host)
+ Pleroma.Repo.transaction(fn ->
+ User.Query.build(%{nickname: "@#{host}"})
+ |> Pleroma.Repo.all()
+ |> Enum.each(fn user ->
+ %{"op" => "delete_user", "user_id" => user.id}
+ |> __MODULE__.new()
+ |> Oban.insert()
+ end)
+ end)
end
@impl true
diff --git a/test/pleroma/instances/instance_test.exs b/test/pleroma/instances/instance_test.exs
@@ -6,9 +6,8 @@ defmodule Pleroma.Instances.InstanceTest do
alias Pleroma.Instances
alias Pleroma.Instances.Instance
alias Pleroma.Repo
- alias Pleroma.Tests.ObanHelpers
- alias Pleroma.Web.CommonAPI
+ use Oban.Testing, repo: Pleroma.Repo
use Pleroma.DataCase
import ExUnit.CaptureLog
@@ -213,32 +212,14 @@ defmodule Pleroma.Instances.InstanceTest do
end
end
- test "delete_users_and_activities/1 deletes remote instance users and activities" do
- [mario, luigi, _peach, wario] =
- users = [
- insert(:user, nickname: "mario@mushroom.kingdom", name: "Mario"),
- insert(:user, nickname: "luigi@mushroom.kingdom", name: "Luigi"),
- insert(:user, nickname: "peach@mushroom.kingdom", name: "Peach"),
- insert(:user, nickname: "wario@greedville.biz", name: "Wario")
- ]
+ test "delete_users_and_activities/1 schedules a job to delete the instance and users" do
+ insert(:user, nickname: "mario@mushroom.kingdom", name: "Mario")
- {:ok, post1} = CommonAPI.post(mario, %{status: "letsa go!"})
- {:ok, post2} = CommonAPI.post(luigi, %{status: "itsa me... luigi"})
- {:ok, post3} = CommonAPI.post(wario, %{status: "WHA-HA-HA!"})
+ {:ok, _job} = Instance.delete_users_and_activities("mushroom.kingdom")
- {:ok, job} = Instance.delete_users_and_activities("mushroom.kingdom")
- :ok = ObanHelpers.perform(job)
-
- [mario, luigi, peach, wario] = Repo.reload(users)
-
- refute mario.is_active
- refute luigi.is_active
- refute peach.is_active
- refute peach.name == "Peach"
-
- assert wario.is_active
- assert wario.name == "Wario"
-
- assert [nil, nil, %{}] = Repo.reload([post1, post2, post3])
+ assert_enqueued(
+ worker: Pleroma.Workers.DeleteWorker,
+ args: %{"op" => "delete_instance", "host" => "mushroom.kingdom"}
+ )
end
end
diff --git a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs
@@ -8,8 +8,6 @@ defmodule Pleroma.Web.AdminAPI.InstanceControllerTest do
import Pleroma.Factory
- alias Pleroma.Repo
- alias Pleroma.Tests.ObanHelpers
alias Pleroma.Web.CommonAPI
setup_all do
@@ -69,19 +67,19 @@ defmodule Pleroma.Web.AdminAPI.InstanceControllerTest do
test "DELETE /instances/:instance", %{conn: conn} do
clear_config([:instance, :admin_privileges], [:instances_delete])
- user = insert(:user, nickname: "lain@lain.com")
- post = insert(:note_activity, user: user)
+ insert(:user, nickname: "lain@lain.com")
response =
conn
|> delete("/api/pleroma/admin/instances/lain.com")
|> json_response(200)
- [:ok] = ObanHelpers.perform_all()
-
assert response == "lain.com"
- refute Repo.reload(user).is_active
- refute Repo.reload(post)
+
+ assert_enqueued(
+ worker: Pleroma.Workers.DeleteWorker,
+ args: %{"op" => "delete_instance", "host" => "lain.com"}
+ )
clear_config([:instance, :admin_privileges], [])
diff --git a/test/pleroma/workers/delete_worker_test.exs b/test/pleroma/workers/delete_worker_test.exs
@@ -0,0 +1,39 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.DeleteWorkerTest do
+ use Pleroma.DataCase, async: true
+ use Oban.Testing, repo: Pleroma.Repo
+
+ import Pleroma.Factory
+
+ alias Pleroma.Instances.Instance
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.Workers.DeleteWorker
+
+ describe "instance deletion" do
+ test "creates individual Oban jobs for each user when deleting an instance" do
+ user1 = insert(:user, nickname: "alice@example.com", name: "Alice")
+ user2 = insert(:user, nickname: "bob@example.com", name: "Bob")
+
+ {:ok, job} = Instance.delete_users_and_activities("example.com")
+
+ assert_enqueued(
+ worker: DeleteWorker,
+ args: %{"op" => "delete_instance", "host" => "example.com"}
+ )
+
+ {:ok, :ok} = ObanHelpers.perform(job)
+
+ delete_user_jobs = all_enqueued(worker: DeleteWorker, args: %{"op" => "delete_user"})
+
+ assert length(delete_user_jobs) == 2
+
+ user_ids = [user1.id, user2.id]
+ job_user_ids = Enum.map(delete_user_jobs, fn job -> job.args["user_id"] end)
+
+ assert Enum.sort(user_ids) == Enum.sort(job_user_ids)
+ end
+ end
+end