From bc24ac3808d7df83fdb4c58d67611fbf8b9a7afe Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Sun, 10 Mar 2024 14:55:21 -0700 Subject: [PATCH] Adds new worker for backfilling data --- lib/pinchflat/workers/data_backfill_worker.ex | 59 +++++++++++++++++++ lib/pinchflat/workers/fast_indexing_worker.ex | 6 +- .../workers/data_backfill_worker_test.exs | 37 ++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 lib/pinchflat/workers/data_backfill_worker.ex create mode 100644 test/pinchflat/workers/data_backfill_worker_test.exs diff --git a/lib/pinchflat/workers/data_backfill_worker.ex b/lib/pinchflat/workers/data_backfill_worker.ex new file mode 100644 index 0000000..bd4d949 --- /dev/null +++ b/lib/pinchflat/workers/data_backfill_worker.ex @@ -0,0 +1,59 @@ +defmodule Pinchflat.Workers.DataBackfillWorker do + @moduledoc false + + use Oban.Worker, + queue: :media_local_metadata, + unique: [period: :infinity, states: [:available, :scheduled, :retryable]], + tags: ["media_item", "media_metadata", "local_metadata", "data_backfill"] + + # This one is going to be a little more self-contained + # instead of relying on outside modules for the methods. + # That's because, for now, these methods are not intended + # to be used elsewhere. + # + # I'm just trying out that pattern and seeing if I like it better + # so this may change. + import Ecto.Query, warn: false + + alias __MODULE__ + alias Pinchflat.Repo + alias Pinchflat.Media.MediaItem + + @impl Oban.Worker + @doc """ + Performs one-off tasks to get data in the right shape. + This can be needed when we add new features or change the way + we store data. Must be idempotent. All new data should already + conform to the expected schema so this should only be needed + for existing data. Still runs periodically to be safe. + + Returns :ok + """ + def perform(%Oban.Job{}) do + backfill_shorts_data() + + reschedule_backfill() + + :ok + end + + defp backfill_shorts_data do + query = + from( + m in MediaItem, + where: fragment("? like ?", m.original_url, "%/shorts/%"), + where: m.short_form_content == false + ) + + Repo.update_all(query, set: [short_form_content: true]) + end + + defp reschedule_backfill do + # Run hourly + next_run_in = 60 * 60 + + %{} + |> DataBackfillWorker.new(schedule_in: next_run_in) + |> Repo.insert_unique_job() + end +end diff --git a/lib/pinchflat/workers/fast_indexing_worker.ex b/lib/pinchflat/workers/fast_indexing_worker.ex index e2f135e..96ac85a 100644 --- a/lib/pinchflat/workers/fast_indexing_worker.ex +++ b/lib/pinchflat/workers/fast_indexing_worker.ex @@ -14,7 +14,11 @@ defmodule Pinchflat.Workers.FastIndexingWorker do @impl Oban.Worker @doc """ - TODO + Kicks off the fast indexing process for a source, reschedules the job to run again + once complete. See `MediaCollectionIndexingWorker` and `MediaIndexingWorker` comments + for more + + Returns :ok | {:ok, :job_exists} | {:ok, %Task{}} """ def perform(%Oban.Job{args: %{"id" => source_id}}) do source = Sources.get_source!(source_id) diff --git a/test/pinchflat/workers/data_backfill_worker_test.exs b/test/pinchflat/workers/data_backfill_worker_test.exs new file mode 100644 index 0000000..470035e --- /dev/null +++ b/test/pinchflat/workers/data_backfill_worker_test.exs @@ -0,0 +1,37 @@ +defmodule Pinchflat.Workers.DataBackfillWorkerTest do + use Pinchflat.DataCase + + import Pinchflat.MediaFixtures + + alias Pinchflat.Workers.DataBackfillWorker + + describe "perform/1" do + test "reschedules itself once complete" do + perform_job(DataBackfillWorker, %{}) + + assert_enqueued(worker: DataBackfillWorker, scheduled_at: now_plus(60, :minutes)) + end + end + + describe "perform/1 when testing backfill_shorts_data" do + test "sets short_form_content to true for media items with shorts in the URL" do + media_item = media_item_with_attachments(%{original_url: "https://example.com/shorts/123"}) + + refute media_item.short_form_content + + perform_job(DataBackfillWorker, %{}) + + assert Repo.reload!(media_item).short_form_content + end + + test "does not set short_form_content to true for media items without shorts in the URL" do + media_item = media_item_with_attachments(%{original_url: "https://example.com/longs/123"}) + + refute media_item.short_form_content + + perform_job(DataBackfillWorker, %{}) + + refute Repo.reload!(media_item).short_form_content + end + end +end