Delivery jobs only checked reachability, so a job queued (or retrying) before the admin rejected or quarantined an instance was still sent. Check should_federate? again when the job runs.
89 lines
2.4 KiB
Elixir
89 lines
2.4 KiB
Elixir
# Pleroma: A lightweight social networking server
|
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
defmodule Pleroma.Workers.PublisherWorker do
|
|
alias Pleroma.Activity
|
|
alias Pleroma.Config
|
|
alias Pleroma.Instances
|
|
alias Pleroma.Web.ActivityPub.Publisher
|
|
alias Pleroma.Web.ActivityPub.Visibility
|
|
alias Pleroma.Web.Federator
|
|
|
|
use Oban.Worker, queue: :federator_outgoing, max_attempts: 13
|
|
|
|
@publish_one_param_keys %{
|
|
"activity_id" => :activity_id,
|
|
"cc" => :cc,
|
|
"inbox" => :inbox,
|
|
"unreachable_since" => :unreachable_since
|
|
}
|
|
|
|
@impl true
|
|
def perform(%Job{args: %{"op" => "publish", "activity_id" => activity_id}}) do
|
|
activity = Activity.get_by_id(activity_id)
|
|
federator().perform(:publish, activity)
|
|
end
|
|
|
|
def perform(%Job{args: %{"op" => "publish_one", "params" => params}} = job) do
|
|
params =
|
|
Enum.reduce(params, %{}, fn {key, value}, acc ->
|
|
case @publish_one_param_keys do
|
|
%{^key => atom_key} -> Map.put(acc, atom_key, value)
|
|
_ -> acc
|
|
end
|
|
end)
|
|
|
|
cond do
|
|
# Cancel / skip the job if this server believed to be unreachable now
|
|
not Instances.reachable?(params.inbox) ->
|
|
{:cancel, :unreachable}
|
|
|
|
# The instance may have been blocked after the job was queued
|
|
not federate?(params) ->
|
|
{:cancel, :rejected}
|
|
|
|
true ->
|
|
case federator().perform(:publish_one, params) do
|
|
{:ok, _} ->
|
|
:ok
|
|
|
|
{:error, _} = error ->
|
|
# Only mark as unreachable on final failure
|
|
if job.attempt == job.max_attempts do
|
|
Instances.set_unreachable(params.inbox)
|
|
end
|
|
|
|
error
|
|
|
|
error ->
|
|
# Unexpected error, may have been client side
|
|
error
|
|
end
|
|
end
|
|
end
|
|
|
|
defp federate?(%{inbox: inbox, activity_id: activity_id}) do
|
|
case Activity.get_by_id(activity_id) do
|
|
%Activity{} = activity -> Publisher.should_federate?(inbox, Visibility.public?(activity))
|
|
nil -> true
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def timeout(_job), do: :timer.seconds(10)
|
|
|
|
defp federator, do: Config.get([:pipeline, :federator], Federator)
|
|
|
|
@base_backoff 15
|
|
@pow 5
|
|
@impl true
|
|
def backoff(%Job{attempt: attempt}) when is_integer(attempt) do
|
|
backoff =
|
|
:math.pow(attempt, @pow) +
|
|
@base_backoff +
|
|
:rand.uniform(2 * @base_backoff) * attempt
|
|
|
|
trunc(backoff)
|
|
end
|
|
end
|