Built a genserver to rename old jobs on boot
This commit is contained in:
parent
abe559c41b
commit
66c1903a41
7 changed files with 502 additions and 27 deletions
401
dump_all.sql
Normal file
401
dump_all.sql
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
73
lib/pinchflat/boot/pre_job_startup_tasks.ex
Normal file
73
lib/pinchflat/boot/pre_job_startup_tasks.ex
Normal 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
|
||||||
|
|
@ -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]],
|
||||||
|
|
|
||||||
25
test/pinchflat/boot/pre_job_startup_tasks_test.exs
Normal file
25
test/pinchflat/boot/pre_job_startup_tasks_test.exs
Normal 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
|
||||||
|
|
@ -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
|
|
||||||
Loading…
Reference in a new issue