@feld@pony i think the only part can actually take some time here is:
User.get_or_fetch_by_ap_id(params["actor"])
because that potentially fetches. So maybe this is a bug, where you have something like a deactivated / blocked user, it tries to fetch them every time and just takes long. We should probably do literally nothing in this controller function though and just throw the stuff into the queue, that would prevent problems with /inbox taking long-ish.
@pony actually that incoming_ap_doc function drops the activity into an Oban queue anyway
I think this should be reworked to reduce the processing here. We're doing all of this validation just to drop the raw data into an Oban job. Why not just accept any well-formed content posted to the Inbox and let the Oban job handle the rest?
If you get spammed with 1000 posts of garbage it's going to increase the load of your system by doing all this validation concurrently instead of just doing it at the limit of concurrent Oban workers for the incoming queue
def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do
with %User{} = recipient <- User.get_cached_by_nickname(nickname),
{:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(params["actor"]),
true <- Utils.recipient_in_message(recipient, actor, params),
params <- Utils.maybe_splice_recipient(recipient.ap_id, params) do
Federator.incoming_ap_doc(params)
json(conn, "ok")
end
end
That should be quick, but I'm wondering if the Federator.incoming_ap_doc(params) function is slow? and also we're not doing anything with results from it, so it could be changed to be non-blocking by wrapping it in a Task.start
I'd be curious to know if your instrumentation shows it's significantly faster if you change that line to: