Handled fast index worker on source update
This commit is contained in:
parent
874a0fe179
commit
79ff5e2275
7 changed files with 125 additions and 36 deletions
|
|
@ -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} ->
|
||||||
|
|
|
||||||
|
|
@ -156,16 +156,14 @@ 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,20 +204,38 @@ 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}} ->
|
||||||
case changeset.changes do
|
maybe_update_slow_indexing_task(changeset, source)
|
||||||
%{index_frequency_minutes: mins} when mins > 0 ->
|
maybe_update_fast_indexing_task(changeset, source)
|
||||||
SourceTasks.kickoff_indexing_task(source)
|
|
||||||
|
|
||||||
%{index_frequency_minutes: _} ->
|
|
||||||
Tasks.delete_pending_tasks_for(source, "FastIndexingWorker")
|
|
||||||
Tasks.delete_pending_tasks_for(source, "MediaIndexingWorker")
|
|
||||||
Tasks.delete_pending_tasks_for(source, "MediaCollectionIndexingWorker")
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
:ok
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, source}
|
{:ok, source}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp maybe_update_slow_indexing_task(changeset, source) do
|
||||||
|
case changeset.changes do
|
||||||
|
%{index_frequency_minutes: mins} when mins > 0 ->
|
||||||
|
SourceTasks.kickoff_indexing_task(source)
|
||||||
|
|
||||||
|
%{index_frequency_minutes: _} ->
|
||||||
|
Tasks.delete_pending_tasks_for(source, "FastIndexingWorker")
|
||||||
|
Tasks.delete_pending_tasks_for(source, "MediaIndexingWorker")
|
||||||
|
Tasks.delete_pending_tasks_for(source, "MediaCollectionIndexingWorker")
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
|
||||||
|
|
@ -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
|
end
|
||||||
# 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
|
@doc """
|
||||||
{:ok, task} -> {:ok, task}
|
Starts tasks for running a fast indexing task for a source's media
|
||||||
end
|
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 """
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()]}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue