SideEffects: Run in transaction.

This fixes race conditions.
This commit is contained in:
lain 2020-04-22 18:40:53 +02:00
parent 1cd38dfffa
commit e62173dfc8
2 changed files with 34 additions and 4 deletions

View file

@ -15,12 +15,15 @@ def handle(object, meta \\ [])
# - Add like to object # - Add like to object
# - Set up notification # - Set up notification
def handle(%{data: %{"type" => "Like"}} = object, meta) do def handle(%{data: %{"type" => "Like"}} = object, meta) do
Pleroma.Repo.transaction(fn ->
liked_object = Object.get_by_ap_id(object.data["object"]) liked_object = Object.get_by_ap_id(object.data["object"])
Utils.add_like_to_object(object, liked_object) Utils.add_like_to_object(object, liked_object)
Notification.create_notifications(object) Notification.create_notifications(object)
{:ok, object, meta} {:ok, object, meta}
end)
|> (fn {:ok, res} -> res end).()
end end
# Nothing to do # Nothing to do

View file

@ -21,6 +21,33 @@ defmodule Pleroma.Web.CommonAPITest do
setup do: clear_config([:instance, :limit]) setup do: clear_config([:instance, :limit])
setup do: clear_config([:instance, :max_pinned_statuses]) setup do: clear_config([:instance, :max_pinned_statuses])
test "favoriting race condition" do
user = insert(:user)
users_serial = insert_list(10, :user)
users = insert_list(10, :user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "."})
users_serial
|> Enum.map(fn user ->
CommonAPI.favorite(user, activity.id)
end)
object = Object.get_by_ap_id(activity.data["object"])
assert object.data["like_count"] == 10
users
|> Enum.map(fn user ->
Task.async(fn ->
CommonAPI.favorite(user, activity.id)
end)
end)
|> Enum.map(&Task.await/1)
object = Object.get_by_ap_id(activity.data["object"])
assert object.data["like_count"] == 20
end
test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do
user = insert(:user) user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) {:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})