Built a genserver to rename old jobs on boot

This commit is contained in:
Kieran Eglin 2024-03-12 10:19:03 -07:00
parent abe559c41b
commit 66c1903a41
No known key found for this signature in database
GPG key ID: 193984967FCF432D
7 changed files with 502 additions and 27 deletions

401
dump_all.sql Normal file

File diff suppressed because one or more lines are too long

View file

@ -11,8 +11,9 @@ defmodule Pinchflat.Application do
PinchflatWeb.Telemetry, PinchflatWeb.Telemetry,
Pinchflat.Repo, Pinchflat.Repo,
# Must be before startup tasks # Must be before startup tasks
Pinchflat.Boot.PreJobStartupTasks,
{Oban, Application.fetch_env!(:pinchflat, Oban)}, {Oban, Application.fetch_env!(:pinchflat, Oban)},
Pinchflat.Boot.StartupTasks, Pinchflat.Boot.PostJobStartupTasks,
{DNSCluster, query: Application.get_env(:pinchflat, :dns_cluster_query) || :ignore}, {DNSCluster, query: Application.get_env(:pinchflat, :dns_cluster_query) || :ignore},
{Phoenix.PubSub, name: Pinchflat.PubSub}, {Phoenix.PubSub, name: Pinchflat.PubSub},
# Start the Finch HTTP client for sending emails # Start the Finch HTTP client for sending emails

View file

@ -1,4 +1,4 @@
defmodule Pinchflat.Boot.StartupTasks do defmodule Pinchflat.Boot.PostJobStartupTasks do
@moduledoc """ @moduledoc """
This module is responsible for running startup tasks on app boot This module is responsible for running startup tasks on app boot
AFTER the job runner has initiallized. AFTER the job runner has initiallized.
@ -12,7 +12,6 @@ defmodule Pinchflat.Boot.StartupTasks do
import Ecto.Query, warn: false import Ecto.Query, warn: false
alias Pinchflat.Repo alias Pinchflat.Repo
alias Pinchflat.Settings
alias Pinchflat.Boot.DataBackfillWorker alias Pinchflat.Boot.DataBackfillWorker
def start_link(opts \\ []) do def start_link(opts \\ []) do
@ -30,17 +29,11 @@ defmodule Pinchflat.Boot.StartupTasks do
""" """
@impl true @impl true
def init(state) do def init(state) do
apply_default_settings()
enqueue_backfill_worker() enqueue_backfill_worker()
{:ok, state} {:ok, state}
end end
defp apply_default_settings do
Settings.fetch!(:onboarding, true)
Settings.fetch!(:pro_enabled, false)
end
defp enqueue_backfill_worker do defp enqueue_backfill_worker do
DataBackfillWorker.cancel_pending_backfill_jobs() DataBackfillWorker.cancel_pending_backfill_jobs()

View file

@ -0,0 +1,73 @@
defmodule Pinchflat.Boot.PreJobStartupTasks do
@moduledoc """
This module is responsible for running startup tasks on app boot
BEFORE the job runner has initiallized.
It's a GenServer because that plays REALLY nicely with the existing
Phoenix supervision tree.
"""
# restart: :temporary means that this process will never be restarted (ie: will run once and then die)
use GenServer, restart: :temporary
import Ecto.Query, warn: false
require Logger
alias Pinchflat.Repo
alias Pinchflat.Settings
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, %{}, opts)
end
@doc """
Runs application startup tasks.
Any code defined here will run every time the application starts. You must
make sure that the code is idempotent and safe to run multiple times.
This is a good place to set up default settings, create initial records, stuff like that.
Should be fast - anything with the potential to be slow should be kicked off as a job instead.
"""
@impl true
def init(state) do
apply_default_settings()
rename_old_job_workers()
{:ok, state}
end
defp apply_default_settings do
Settings.fetch!(:onboarding, true)
Settings.fetch!(:pro_enabled, false)
end
# As part of a large refactor, I ended up moving a bunch of workers around. This
# is a problem because the workers are stored in the database and the runner
# will try to run the OLD jobs. This is also why these tasks run before the job
# runner starts up.
#
# Can be removed after a few months (created: 2024-03-12)
defp rename_old_job_workers do
# [ [old_name, new_name], ...]
rename_map = [
["Pinchflat.Workers.MediaIndexingWorker", "Pinchflat.FastIndexing.MediaIndexingWorker"],
["Pinchflat.Workers.MediaDownloadWorker", "Pinchflat.Downloading.MediaDownloadWorker"],
["Pinchflat.Workers.FilesystemDataWorker", "Pinchflat.Filesystem.FilesystemDataWorker"],
["Pinchflat.Workers.FastIndexingWorker", "Pinchflat.FastIndexing.FastIndexingWorker"],
["Pinchflat.Workers.MediaCollectionIndexingWorker", "Pinchflat.SlowIndexing.MediaCollectionIndexingWorker"],
["Pinchflat.Workers.DataBackfillWorker", "Pinchflat.Boot.DataBackfillWorker"]
]
jobs_renamed =
Enum.reduce(rename_map, 0, fn [old_name, new_name], acc ->
{count, _} =
Oban.Job
|> where(worker: ^old_name)
|> Repo.update_all(set: [worker: new_name])
acc + count
end)
Logger.info("Renamed #{jobs_renamed} old job workers")
end
end

View file

@ -1,8 +1,6 @@
defmodule Pinchflat.FastIndexing.MediaIndexingWorker do defmodule Pinchflat.FastIndexing.MediaIndexingWorker do
@moduledoc false @moduledoc false
# TODO: make a startup task to rename all existing workers so they still run
use Oban.Worker, use Oban.Worker,
queue: :media_indexing, queue: :media_indexing,
unique: [period: :infinity, states: [:available, :scheduled, :retryable]], unique: [period: :infinity, states: [:available, :scheduled, :retryable]],

View file

@ -0,0 +1,25 @@
defmodule Pinchflat.Boot.PreJobStartupTasksTest do
use Pinchflat.DataCase
alias Pinchflat.Settings
alias Pinchflat.Settings.Setting
alias Pinchflat.Boot.PreJobStartupTasks
describe "apply_default_settings" do
setup do
Repo.delete_all(Setting)
:ok
end
test "sets default settings" do
assert_raise Ecto.NoResultsError, fn -> Settings.get!(:onboarding) end
assert_raise Ecto.NoResultsError, fn -> Settings.get!(:pro_enabled) end
PreJobStartupTasks.start_link()
assert Settings.get!(:onboarding)
refute Settings.get!(:pro_enabled)
end
end
end

View file

@ -1,16 +0,0 @@
defmodule Pinchflat.Boot.StartupTasksTest do
use Pinchflat.DataCase
alias Pinchflat.Settings
# Since this runs on app boot (even in the test env),
# any actions in the `init/1` function will already have
# run. So we can only test the side effects of those actions,
# rather than the actions themselves.
describe "apply_default_settings" do
test "sets default settings" do
assert Settings.get!(:onboarding) == true
end
end
end