Handled fast index worker on source update

This commit is contained in:
Kieran Eglin 2024-03-09 19:36:15 -08:00
parent 874a0fe179
commit 79ff5e2275
No known key found for this signature in database
GPG key ID: 193984967FCF432D
7 changed files with 125 additions and 36 deletions

View file

@ -3,6 +3,8 @@ defmodule Pinchflat.Api.YoutubeRss do
Methods for interacting with YouTube RSS feeds Methods for interacting with YouTube RSS feeds
""" """
require Logger
alias Pinchflat.Sources.Source alias Pinchflat.Sources.Source
@doc """ @doc """
@ -11,6 +13,8 @@ defmodule Pinchflat.Api.YoutubeRss do
Returns {:ok, [binary()]} | {:error, binary()} Returns {:ok, [binary()]} | {:error, binary()}
""" """
def get_recent_media_ids_from_rss(%Source{} = source) do def get_recent_media_ids_from_rss(%Source{} = source) do
Logger.debug("Fetching recent media IDs from YouTube RSS feed for source: #{source.collection_id}")
case http_client().get(rss_url_for_source(source)) do case http_client().get(rss_url_for_source(source)) do
{:ok, response} -> {:ok, response} ->
response = to_string(response) response = to_string(response)
@ -25,6 +29,8 @@ defmodule Pinchflat.Api.YoutubeRss do
|> Enum.filter(&(String.length(&1) > 0)) |> Enum.filter(&(String.length(&1) > 0))
|> Enum.uniq() |> Enum.uniq()
Logger.debug("Media ids fetched from RSS: #{inspect(media_ids)}")
{:ok, media_ids} {:ok, media_ids}
{:error, _reason} -> {:error, _reason} ->

View file

@ -156,15 +156,13 @@ defmodule Pinchflat.Sources do
defp maybe_change_indexing_frequency(changeset) do defp maybe_change_indexing_frequency(changeset) do
fast_index = Ecto.Changeset.get_field(changeset, :fast_index) fast_index = Ecto.Changeset.get_field(changeset, :fast_index)
case {changeset.changes, fast_index} do if fast_index do
{%{index_frequency_minutes: _}, true} ->
Ecto.Changeset.put_change( Ecto.Changeset.put_change(
changeset, changeset,
:index_frequency_minutes, :index_frequency_minutes,
Source.index_frequency_when_fast_indexing() Source.index_frequency_when_fast_indexing()
) )
else
_ ->
changeset changeset
end end
end end
@ -206,6 +204,14 @@ defmodule Pinchflat.Sources do
# If the record has been persisted, only run indexing if the # If the record has been persisted, only run indexing if the
# indexing frequency has been changed and is now greater than 0 # indexing frequency has been changed and is now greater than 0
%{__meta__: %{state: :loaded}} -> %{__meta__: %{state: :loaded}} ->
maybe_update_slow_indexing_task(changeset, source)
maybe_update_fast_indexing_task(changeset, source)
end
{:ok, source}
end
defp maybe_update_slow_indexing_task(changeset, source) do
case changeset.changes do case changeset.changes do
%{index_frequency_minutes: mins} when mins > 0 -> %{index_frequency_minutes: mins} when mins > 0 ->
SourceTasks.kickoff_indexing_task(source) SourceTasks.kickoff_indexing_task(source)
@ -220,6 +226,16 @@ defmodule Pinchflat.Sources do
end end
end end
{:ok, source} defp maybe_update_fast_indexing_task(changeset, source) do
case changeset.changes do
%{fast_index: true} ->
SourceTasks.kickoff_fast_indexing_task(source)
%{fast_index: false} ->
Tasks.delete_pending_tasks_for(source, "FastIndexingWorker")
_ ->
:ok
end
end end
end end

View file

@ -14,6 +14,7 @@ defmodule Pinchflat.Tasks.SourceTasks do
alias Pinchflat.Sources.Source alias Pinchflat.Sources.Source
alias Pinchflat.Api.YoutubeRss alias Pinchflat.Api.YoutubeRss
alias Pinchflat.Media.MediaItem alias Pinchflat.Media.MediaItem
alias Pinchflat.Workers.FastIndexingWorker
alias Pinchflat.Workers.MediaDownloadWorker alias Pinchflat.Workers.MediaDownloadWorker
alias Pinchflat.Workers.MediaIndexingWorker alias Pinchflat.Workers.MediaIndexingWorker
alias Pinchflat.YtDlp.Backend.MediaCollection alias Pinchflat.YtDlp.Backend.MediaCollection
@ -37,11 +38,25 @@ defmodule Pinchflat.Tasks.SourceTasks do
# Schedule this one immediately, but future ones will be on an interval # Schedule this one immediately, but future ones will be on an interval
|> MediaCollectionIndexingWorker.new() |> MediaCollectionIndexingWorker.new()
|> Tasks.create_job_with_task(source) |> Tasks.create_job_with_task(source)
|> case do
# This should never return {:error, :duplicate_job} since we just deleted
# any pending tasks. I'm being assertive about it so it's obvious if I'm wrong
{:ok, task} -> {:ok, task}
end end
@doc """
Starts tasks for running a fast indexing task for a source's media
regardless of the source's fast_index state. It's assumed the
caller will check for fast_index.
This is used for running fast index tasks on update. On creation, the
fast index is enqueued after the slow index is complete.
Returns {:ok, %Task{}}.
"""
def kickoff_fast_indexing_task(%Source{} = source) do
Tasks.delete_pending_tasks_for(source, "FastIndexingWorker")
%{id: source.id}
# Schedule this one immediately, but future ones will be on an interval
|> FastIndexingWorker.new()
|> Tasks.create_job_with_task(source)
end end
@doc """ @doc """

View file

@ -3,8 +3,9 @@ defmodule PinchflatWeb.Sources.SourceController do
alias Pinchflat.Repo alias Pinchflat.Repo
alias Pinchflat.Media alias Pinchflat.Media
alias Pinchflat.Profiles alias Pinchflat.Tasks
alias Pinchflat.Sources alias Pinchflat.Sources
alias Pinchflat.Profiles
alias Pinchflat.Sources.Source alias Pinchflat.Sources.Source
def index(conn, _params) do def index(conn, _params) do
@ -43,15 +44,18 @@ defmodule PinchflatWeb.Sources.SourceController do
end end
def show(conn, %{"id" => id}) do def show(conn, %{"id" => id}) do
source = source = Repo.preload(Sources.get_source!(id), :media_profile)
id
|> Sources.get_source!()
|> Repo.preload([:media_profile, tasks: [:job]])
pending_tasks = Repo.preload(Tasks.list_pending_tasks_for(:source_id, source.id), :job)
pending_media = Media.list_pending_media_items_for(source, limit: 100) pending_media = Media.list_pending_media_items_for(source, limit: 100)
downloaded_media = Media.list_downloaded_media_items_for(source, limit: 100) downloaded_media = Media.list_downloaded_media_items_for(source, limit: 100)
render(conn, :show, source: source, pending_media: pending_media, downloaded_media: downloaded_media) render(conn, :show,
source: source,
pending_tasks: pending_tasks,
pending_media: pending_media,
downloaded_media: downloaded_media
)
end end
def edit(conn, %{"id" => id}) do def edit(conn, %{"id" => id}) do

View file

@ -84,9 +84,9 @@
<p class="text-black dark:text-white">Nothing Here!</p> <p class="text-black dark:text-white">Nothing Here!</p>
<% end %> <% end %>
</:tab> </:tab>
<:tab title="Tasks"> <:tab title="Pending Tasks">
<%= if match?([_|_], @source.tasks) do %> <%= if match?([_|_], @pending_tasks) do %>
<.table rows={@source.tasks} table_class="text-black dark:text-white"> <.table rows={@pending_tasks} table_class="text-black dark:text-white">
<:col :let={task} label="Worker"> <:col :let={task} label="Worker">
<%= task.job.worker %> <%= task.job.worker %>
</:col> </:col>

View file

@ -324,6 +324,26 @@ defmodule Pinchflat.SourcesTest do
refute_enqueued(worker: MediaDownloadWorker) refute_enqueued(worker: MediaDownloadWorker)
end end
test "enabling fast_index will schedule a fast indexing task" do
source = source_fixture(fast_index: false)
update_attrs = %{fast_index: true}
refute_enqueued(worker: FastIndexingWorker)
assert {:ok, %Source{}} = Sources.update_source(source, update_attrs)
assert_enqueued(worker: FastIndexingWorker, args: %{"id" => source.id})
end
test "disabling fast_index will cancel the fast indexing task" do
source = source_fixture(fast_index: true)
update_attrs = %{fast_index: false}
{:ok, job} = Oban.insert(FastIndexingWorker.new(%{"id" => source.id}))
task_fixture(source_id: source.id, job_id: job.id)
assert_enqueued(worker: FastIndexingWorker, args: %{"id" => source.id})
assert {:ok, %Source{}} = Sources.update_source(source, update_attrs)
refute_enqueued(worker: FastIndexingWorker)
end
test "updates with invalid data returns error changeset" do test "updates with invalid data returns error changeset" do
source = source_fixture() source = source_fixture()

View file

@ -66,6 +66,34 @@ defmodule Pinchflat.Tasks.SourceTasksTest do
end end
end end
describe "kickoff_fast_indexing_task/1" do
test "it schedules a job" do
source = source_fixture()
assert {:ok, _} = SourceTasks.kickoff_fast_indexing_task(source)
assert_enqueued(worker: FastIndexingWorker, args: %{"id" => source.id})
end
test "it creates and attaches a task" do
source = source_fixture()
assert {:ok, %Task{} = task} = SourceTasks.kickoff_fast_indexing_task(source)
assert task.source_id == source.id
end
test "it deletes any fast indexing tasks for the source" do
source = source_fixture()
{:ok, job} = Oban.insert(FastIndexingWorker.new(%{"id" => source.id}))
task = task_fixture(source_id: source.id, job_id: job.id)
assert {:ok, _} = SourceTasks.kickoff_fast_indexing_task(source)
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(task) end
end
end
describe "kickoff_indexing_tasks_from_youtube_rss_feed/1" do describe "kickoff_indexing_tasks_from_youtube_rss_feed/1" do
setup do setup do
{:ok, [source: source_fixture()]} {:ok, [source: source_fixture()]}