diff --git a/Gemfile b/Gemfile index 7cfa7a13..dfd5981b 100644 --- a/Gemfile +++ b/Gemfile @@ -14,7 +14,7 @@ gem 'berkeley_library-util', '~> 0.3' gem 'bootstrap' gem 'dotenv-rails', '~> 2.8.1', require: 'dotenv/rails-now' gem 'faraday' -gem 'good_job', '~> 3.99' +gem 'good_job', '~> 4.0' gem 'ipaddress' gem 'jaro_winkler', '~> 1.5.5' gem 'jquery-rails' diff --git a/Gemfile.lock b/Gemfile.lock index 175af8f0..926fca71 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -187,13 +187,13 @@ GEM raabro (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) - good_job (3.99.1) - activejob (>= 6.0.0) - activerecord (>= 6.0.0) - concurrent-ruby (>= 1.0.2) - fugit (>= 1.1) - railties (>= 6.0.0) - thor (>= 0.14.1) + good_job (4.13.2) + activejob (>= 6.1.0) + activerecord (>= 6.1.0) + concurrent-ruby (>= 1.3.1) + fugit (>= 1.11.0) + railties (>= 6.1.0) + thor (>= 1.0.0) hashdiff (1.0.1) hashie (5.0.0) http-accept (1.7.0) @@ -530,7 +530,7 @@ DEPENDENCIES database_cleaner-active_record (~> 2.1) dotenv-rails (~> 2.8.1) faraday - good_job (~> 3.99) + good_job (~> 4.0) ipaddress jaro_winkler (~> 1.5.5) jquery-rails diff --git a/db/migrate/20260219014102_add_jobs_finished_at_to_good_job_batches.rb b/db/migrate/20260219014102_add_jobs_finished_at_to_good_job_batches.rb new file mode 100644 index 00000000..09c3e832 --- /dev/null +++ b/db/migrate/20260219014102_add_jobs_finished_at_to_good_job_batches.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddJobsFinishedAtToGoodJobBatches < ActiveRecord::Migration[7.1] + def change + reversible do |dir| + dir.up do + # Ensure this incremental update migration is idempotent + # with monolithic install migration. + return if connection.column_exists?(:good_job_batches, :jobs_finished_at) + end + end + + change_table :good_job_batches do |t| + t.datetime :jobs_finished_at + end + end +end diff --git a/db/migrate/20260219014103_add_index_good_jobs_concurrency_key_created_at.rb b/db/migrate/20260219014103_add_index_good_jobs_concurrency_key_created_at.rb new file mode 100644 index 00000000..2e858eb7 --- /dev/null +++ b/db/migrate/20260219014103_add_index_good_jobs_concurrency_key_created_at.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddIndexGoodJobsConcurrencyKeyCreatedAt < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + reversible do |dir| + dir.up do + # Ensure this incremental update migration is idempotent + # with monolithic install migration. + return if connection.index_exists? :good_jobs, [:concurrency_key, :created_at] + end + end + + add_index :good_jobs, [:concurrency_key, :created_at], algorithm: :concurrently + end +end diff --git a/db/migrate/20260219014104_add_index_good_jobs_job_class.rb b/db/migrate/20260219014104_add_index_good_jobs_job_class.rb new file mode 100644 index 00000000..b48813ca --- /dev/null +++ b/db/migrate/20260219014104_add_index_good_jobs_job_class.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddIndexGoodJobsJobClass < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + reversible do |dir| + dir.up do + # Ensure this incremental update migration is idempotent + # with monolithic install migration. + return if connection.index_exists? :good_jobs, :job_class + end + end + + add_index :good_jobs, :job_class, algorithm: :concurrently + end +end \ No newline at end of file diff --git a/db/migrate/20260219014105_add_index_good_jobs_finished_at_for_cleanup.rb b/db/migrate/20260219014105_add_index_good_jobs_finished_at_for_cleanup.rb new file mode 100644 index 00000000..5bd463d1 --- /dev/null +++ b/db/migrate/20260219014105_add_index_good_jobs_finished_at_for_cleanup.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddIndexGoodJobsFinishedAtForCleanup < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + reversible do |dir| + dir.up do + # Ensure this incremental update migration is idempotent + # with monolithic install migration. + return if connection.index_exists? :good_jobs, [:finished_at], name: :index_good_jobs_jobs_on_finished_at_only + end + end + + add_index :good_jobs, [:finished_at], where: "finished_at IS NOT NULL", name: :index_good_jobs_jobs_on_finished_at_only, algorithm: :concurrently + end +end diff --git a/db/migrate/20260219014106_remove_extraneous_finished_at_index.rb b/db/migrate/20260219014106_remove_extraneous_finished_at_index.rb new file mode 100644 index 00000000..7542326a --- /dev/null +++ b/db/migrate/20260219014106_remove_extraneous_finished_at_index.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class RemoveExtraneousFinishedAtIndex < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + reversible do |dir| + dir.up do + # Ensure this incremental update migration is idempotent + # with monolithic install migration. + return unless connection.index_exists? :good_jobs, [:finished_at], name: :index_good_jobs_jobs_on_finished_at + end + end + + remove_index :good_jobs, [:finished_at], where: "retried_good_job_id IS NULL AND finished_at IS NOT NULL", name: :index_good_jobs_jobs_on_finished_at, algorithm: :concurrently + end +end diff --git a/db/schema.rb b/db/schema.rb index fdcf65e9..0e2c3eb0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2026_01_28_024814) do +ActiveRecord::Schema[7.1].define(version: 2026_02_19_014106) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -72,6 +72,7 @@ t.datetime "enqueued_at" t.datetime "discarded_at" t.datetime "finished_at" + t.datetime "jobs_finished_at" end create_table "good_job_executions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| @@ -134,10 +135,12 @@ t.index ["active_job_id", "created_at"], name: "index_good_jobs_on_active_job_id_and_created_at" t.index ["batch_callback_id"], name: "index_good_jobs_on_batch_callback_id", where: "(batch_callback_id IS NOT NULL)" t.index ["batch_id"], name: "index_good_jobs_on_batch_id", where: "(batch_id IS NOT NULL)" + t.index ["concurrency_key", "created_at"], name: "index_good_jobs_on_concurrency_key_and_created_at" t.index ["concurrency_key"], name: "index_good_jobs_on_concurrency_key_when_unfinished", where: "(finished_at IS NULL)" t.index ["cron_key", "created_at"], name: "index_good_jobs_on_cron_key_and_created_at_cond", where: "(cron_key IS NOT NULL)" t.index ["cron_key", "cron_at"], name: "index_good_jobs_on_cron_key_and_cron_at_cond", unique: true, where: "(cron_key IS NOT NULL)" - t.index ["finished_at"], name: "index_good_jobs_jobs_on_finished_at", where: "((retried_good_job_id IS NULL) AND (finished_at IS NOT NULL))" + t.index ["finished_at"], name: "index_good_jobs_jobs_on_finished_at_only", where: "(finished_at IS NOT NULL)" + t.index ["job_class"], name: "index_good_jobs_on_job_class" t.index ["labels"], name: "index_good_jobs_on_labels", where: "(labels IS NOT NULL)", using: :gin t.index ["locked_by_id"], name: "index_good_jobs_on_locked_by_id", where: "(locked_by_id IS NOT NULL)" t.index ["priority", "created_at"], name: "index_good_job_jobs_for_candidate_lookup", where: "(finished_at IS NULL)"