Put rich media processing in a Task
authorFloatingGhost <hannah@coffee-and-dreams.uk>
Fri, 30 Dec 2022 20:11:53 +0000 (20:11 +0000)
committerFloatingGhost <hannah@coffee-and-dreams.uk>
Fri, 30 Dec 2022 20:11:53 +0000 (20:11 +0000)
lib/pleroma/web/mastodon_api/views/status_view.ex
lib/pleroma/web/rich_media/parser.ex
test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
test/pleroma/web/rich_media/helpers_test.exs
test/pleroma/web/rich_media/parser_test.exs

index cc58f803e6b2c7773c96f6b1ad21d7ce0f7830ee..8fbf9b6d91b199d3dc11f17442d45acb808ff798 100644 (file)
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
   # to fetch the preview. However it should be fine considering
   # pagination is restricted to 40 activities at a time
   defp fetch_rich_media_for_activities(activities) do
-    Enum.each(activities, fn activity ->
+    Enum.map(activities, fn activity ->
       spawn(fn ->
         Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
       end)
index d6b54943b40ee2ee0289ef648a1f2cdf4a79a3ba..1d4cad0100e2ebcb8092b96555f5b5dfa938fa70 100644 (file)
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.RichMedia.Parser do
 
   if Pleroma.Config.get(:env) == :test do
     @spec parse(String.t()) :: {:ok, map()} | {:error, any()}
-    def parse(url), do: parse_url(url)
+    def parse(url), do: parse_with_timeout(url)
   else
     @spec parse(String.t()) :: {:ok, map()} | {:error, any()}
     def parse(url) do
@@ -27,7 +27,7 @@ defmodule Pleroma.Web.RichMedia.Parser do
 
     defp get_cached_or_parse(url) do
       case @cachex.fetch(:rich_media_cache, url, fn ->
-             case parse_url(url) do
+             case parse_with_timeout(url) do
                {:ok, _} = res ->
                  {:commit, res}
 
@@ -141,6 +141,21 @@ defmodule Pleroma.Web.RichMedia.Parser do
     end
   end
 
+  def parse_with_timeout(url) do
+    try do
+      task =
+        Task.Supervisor.async_nolink(Pleroma.TaskSupervisor, fn ->
+          parse_url(url)
+        end)
+
+      Task.await(task, 5000)
+    catch
+      :exit, {:timeout, _} ->
+        Logger.warn("Timeout while fetching rich media for #{url}")
+        {:error, :timeout}
+    end
+  end
+
   defp maybe_parse(html) do
     Enum.reduce_while(parsers(), %{}, fn parser, acc ->
       case parser.parse(html, acc) do
index d76db0c0dcd3c6f75a46ab3ad2df9f499c618ea4..7931d1d697c407026f365762b218f5587c30c129 100644 (file)
@@ -326,7 +326,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
     test "fake statuses' preview card is not cached", %{conn: conn} do
       clear_config([:rich_media, :enabled], true)
 
-      Tesla.Mock.mock(fn
+      Tesla.Mock.mock_global(fn
         %{
           method: :get,
           url: "https://example.com/twitter-card"
index 689854fb65ae57106d4588601b724eb31a929c2c..c6c3ffd6c6ee372fdd02fabb070464b783c95c09 100644 (file)
@@ -12,7 +12,7 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
   import Tesla.Mock
 
   setup do
-    mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+    mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
 
     :ok
   end
index 2fe7f1b0b7e9727fa0c3156675ff4a097f6360ef..b6444ac82929c2d6ac3131efcbbe3d87789470bc 100644 (file)
@@ -8,7 +8,7 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
   alias Pleroma.Web.RichMedia.Parser
 
   setup do
-    Tesla.Mock.mock(fn
+    Tesla.Mock.mock_global(fn
       %{
         method: :get,
         url: "http://example.com/ogp"