diff --git a/lib/pinchflat/metadata/source_metadata_storage_worker.ex b/lib/pinchflat/metadata/source_metadata_storage_worker.ex index bdc81b1..2500324 100644 --- a/lib/pinchflat/metadata/source_metadata_storage_worker.ex +++ b/lib/pinchflat/metadata/source_metadata_storage_worker.ex @@ -4,7 +4,10 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorker do use Oban.Worker, queue: :remote_metadata, tags: ["media_source", "source_metadata", "remote_metadata"], - max_attempts: 1 + max_attempts: 1, + # This is the only thing stopping this job from calling itself + # in an infinite loop. + unique: [period: 600] alias __MODULE__ alias Pinchflat.Repo @@ -27,16 +30,19 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorker do |> Tasks.create_job_with_task(source) end - @impl Oban.Worker @doc """ Fetches and stores metadata for a source in the secret metadata location. Returns :ok """ + @impl Oban.Worker def perform(%Oban.Job{args: %{"id" => source_id}}) do source = Repo.preload(Sources.get_source!(source_id), :metadata) {:ok, metadata} = MediaCollection.get_source_metadata(source.original_url) + # Since updating a source kicks this job off again, we enforce job uniqueness (above) + # to once, per source, per x minutes. This is to prevent a job from calling itself + # in an infinite loop. Sources.update_source(source, %{ metadata: %{ metadata_filepath: MetadataFileHelpers.compress_and_store_metadata_for(source, metadata) diff --git a/test/pinchflat/metadata/source_metadata_storage_worker_test.exs b/test/pinchflat/metadata/source_metadata_storage_worker_test.exs index c3a4d2b..48047b5 100644 --- a/test/pinchflat/metadata/source_metadata_storage_worker_test.exs +++ b/test/pinchflat/metadata/source_metadata_storage_worker_test.exs @@ -51,5 +51,28 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do assert metadata == %{"title" => "test"} end + + test "won't call itself in an infinite loop" do + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "{}"} end) + source = source_fixture() + + perform_job(SourceMetadataStorageWorker, %{id: source.id}) + perform_job(SourceMetadataStorageWorker, %{id: source.id}) + + assert [_] = all_enqueued(worker: SourceMetadataStorageWorker) + end + + test "doesn't prevent over source jobs from running" do + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "{}"} end) + source_1 = source_fixture() + source_2 = source_fixture() + + perform_job(SourceMetadataStorageWorker, %{id: source_1.id}) + perform_job(SourceMetadataStorageWorker, %{id: source_1.id}) + perform_job(SourceMetadataStorageWorker, %{id: source_2.id}) + perform_job(SourceMetadataStorageWorker, %{id: source_2.id}) + + assert [_, _] = all_enqueued(worker: SourceMetadataStorageWorker) + end end end