Do object insertion through Cachex
authorlain <lain@soykaf.club>
Sat, 9 Feb 2019 21:01:08 +0000 (22:01 +0100)
committerlain <lain@soykaf.club>
Sat, 9 Feb 2019 21:01:08 +0000 (22:01 +0100)
So we don't flood our postgres logs with errors. Should also make things
slightly faster.

lib/pleroma/object.ex
lib/pleroma/web/activity_pub/utils.ex
lib/pleroma/web/twitter_api/twitter_api.ex
test/object_test.exs

index 7b46a3b05266fd47d8a3fa928975c4d9cc54e018..96079cf229a7e24af2d2ebb97f098ac06610840f 100644 (file)
@@ -13,9 +13,29 @@ defmodule Pleroma.Object do
     timestamps()
   end
 
+  def insert_or_get(cng) do
+    {_, data} = fetch_field(cng, :data)
+    id = data["id"] || data[:id]
+    key = "object:#{id}"
+
+    fetcher = fn _ ->
+      with nil <- get_by_ap_id(id),
+           {:ok, object} <- Repo.insert(cng) do
+        {:commit, object}
+      else
+        %Object{} = object -> {:commit, object}
+        e -> {:ignore, e}
+      end
+    end
+
+    with {state, object} when state in [:commit, :ok] <- Cachex.fetch(:object_cache, key, fetcher) do
+      {:ok, object}
+    end
+  end
+
   def create(data) do
     Object.change(%Object{}, %{data: data})
-    |> Repo.insert()
+    |> insert_or_get()
   end
 
   def change(struct, params \\ %{}) do
index 4a2cc67384836a31f69c68531a552905a74b6a15..134701e80597f95002fa79c9a0fdc95bdbf39e59 100644 (file)
@@ -134,14 +134,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do
     context = context || generate_id("contexts")
     changeset = Object.context_mapping(context)
 
-    case Repo.insert(changeset) do
-      {:ok, object} ->
-        object
-
-      # This should be solved by an upsert, but it seems ecto
-      # has problems accessing the constraint inside the jsonb.
-      {:error, _} ->
-        Object.get_cached_by_ap_id(context)
+    with {:ok, object} <- Object.insert_or_get(changeset) do
+      object
     end
   end
 
index 7d00c01a164a709d9229b31b00ae6f932c40e789..ddd5c5cfbb1180a37fea74d16478fc2a13913529 100644 (file)
@@ -305,16 +305,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
     else
       _e ->
         changeset = Object.context_mapping(context)
-
-        case Repo.insert(changeset) do
-          {:ok, %{id: id}} ->
-            id
-
-          # This should be solved by an upsert, but it seems ecto
-          # has problems accessing the constraint inside the jsonb.
-          {:error, _} ->
-            Object.get_cached_by_ap_id(context).id
-        end
+        {:ok, object} = Object.insert_or_get(changeset)
+        object.id
     end
   end
 
index 72194975d7b25405bae21fedb1c7d9e93d0dedda..ab643101253fda533f61150aea58f1c222dbd6f4 100644 (file)
@@ -57,4 +57,32 @@ defmodule Pleroma.ObjectTest do
       assert cached_object.data["type"] == "Tombstone"
     end
   end
+
+  describe "insert_or_get" do
+    test "inserting the same object twice (by id) just returns the original object" do
+      data = %{data: %{"id" => Ecto.UUID.generate()}}
+      cng = Object.change(%Object{}, data)
+      {:ok, object} = Object.insert_or_get(cng)
+      {:ok, second_object} = Object.insert_or_get(cng)
+
+      Cachex.clear(:object_cache)
+      {:ok, third_object} = Object.insert_or_get(cng)
+
+      assert object == second_object
+      assert object == third_object
+    end
+  end
+
+  describe "create" do
+    test "inserts an object for a given data set" do
+      data = %{"id" => Ecto.UUID.generate()}
+
+      {:ok, object} = Object.create(data)
+      assert object.data["id"] == data["id"]
+
+      # Works when doing it twice.
+      {:ok, object} = Object.create(data)
+      assert object.data["id"] == data["id"]
+    end
+  end
 end