diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index dd12f094a..54f824d00 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,18 +1,43 @@ # This configuration was generated by # `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 400` -# on 2024-01-10 04:25:30 UTC using RuboCop version 1.59.0. +# on 2024-03-14 03:12:58 UTC using RuboCop version 1.62.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 2 +# Offense count: 6 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. +# SupportedHashRocketStyles: key, separator, table +# SupportedColonStyles: key, separator, table +# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit +Layout/HashAlignment: + Exclude: + - 'db/migrate/20240314031219_recreate_good_job_cron_indexes_with_conditional.rb' + - 'db/migrate/20240314031221_create_good_job_labels_index.rb' + - 'db/migrate/20240314031223_create_index_good_job_jobs_for_candidate_lookup.rb' + +# Offense count: 28 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. # URISchemes: http, https Layout/LineLength: Exclude: - 'db/migrate/20230801025231_create_index_good_jobs_jobs_on_priority_created_at_when_unfinished.rb' + - 'db/migrate/20240314031219_recreate_good_job_cron_indexes_with_conditional.rb' + - 'db/migrate/20240314031221_create_good_job_labels_index.rb' + - 'db/migrate/20240314031222_remove_good_job_active_id_index.rb' + - 'db/migrate/20240314031223_create_index_good_job_jobs_for_candidate_lookup.rb' + +# Offense count: 19 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowMultilineFinalElement. +Layout/MultilineMethodArgumentLineBreaks: + Exclude: + - 'db/migrate/20240314031219_recreate_good_job_cron_indexes_with_conditional.rb' + - 'db/migrate/20240314031221_create_good_job_labels_index.rb' + - 'db/migrate/20240314031223_create_index_good_job_jobs_for_candidate_lookup.rb' # Offense count: 9 # This cop supports unsafe autocorrection (--autocorrect-all). @@ -30,12 +55,26 @@ Lint/NumberConversion: - 'spec/models/feed_spec.rb' - 'spec/models/story_spec.rb' -# Offense count: 2 +# Offense count: 3 # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max. Metrics/AbcSize: Exclude: - 'db/migrate/20230801025232_create_good_job_batches.rb' - 'db/migrate/20230801025233_create_good_job_executions.rb' + - 'db/migrate/20240314031219_recreate_good_job_cron_indexes_with_conditional.rb' + +# Offense count: 1 +# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode. +# AllowedMethods: refine +Metrics/BlockLength: + Exclude: + - 'db/migrate/20240314031219_recreate_good_job_cron_indexes_with_conditional.rb' + +# Offense count: 1 +# Configuration parameters: AllowedMethods, AllowedPatterns, Max. +Metrics/CyclomaticComplexity: + Exclude: + - 'db/migrate/20240314031219_recreate_good_job_cron_indexes_with_conditional.rb' # Offense count: 5 # Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns. @@ -46,6 +85,12 @@ Metrics/MethodLength: - 'app/utils/opml_parser.rb' - 'app/utils/sample_story.rb' +# Offense count: 1 +# Configuration parameters: AllowedMethods, AllowedPatterns, Max. +Metrics/PerceivedComplexity: + Exclude: + - 'db/migrate/20240314031219_recreate_good_job_cron_indexes_with_conditional.rb' + # Offense count: 2 # Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros. # NamePrefix: is_, has_, have_ @@ -78,7 +123,7 @@ RSpec/DescribeClass: Exclude: - 'spec/integration/feed_importing_spec.rb' -# Offense count: 32 +# Offense count: 33 # Configuration parameters: Max, CountAsOne. RSpec/ExampleLength: Exclude: @@ -98,14 +143,13 @@ RSpec/ExampleLength: - 'spec/utils/feed_discovery_spec.rb' - 'spec/utils/opml_parser_spec.rb' -# Offense count: 17 +# Offense count: 16 # Configuration parameters: EnforcedStyle. # SupportedStyles: allow, expect RSpec/MessageExpectation: Exclude: - 'spec/commands/feed/fetch_one_spec.rb' - 'spec/models/migration_status_spec.rb' - - 'spec/repositories/feed_repository_spec.rb' - 'spec/repositories/story_repository_spec.rb' - 'spec/tasks/remove_old_stories_spec.rb' - 'spec/utils/i18n_support_spec.rb' @@ -125,18 +169,13 @@ RSpec/MultipleExpectations: - 'spec/utils/i18n_support_spec.rb' - 'spec/utils/opml_parser_spec.rb' -# Offense count: 45 +# Offense count: 35 # Configuration parameters: AllowSubject, Max. RSpec/MultipleMemoizedHelpers: Exclude: - - 'spec/commands/feed/import_from_opml_spec.rb' - - 'spec/commands/fever_api/read_favicons_spec.rb' - - 'spec/commands/fever_api/write_mark_feed_spec.rb' - - 'spec/commands/story/mark_as_read_spec.rb' - 'spec/helpers/url_helpers_spec.rb' - 'spec/integration/feed_importing_spec.rb' - 'spec/models/story_spec.rb' - - 'spec/repositories/feed_repository_spec.rb' - 'spec/repositories/story_repository_spec.rb' - 'spec/requests/feeds_controller_spec.rb' - 'spec/requests/imports_controller_spec.rb' @@ -146,12 +185,11 @@ RSpec/MultipleMemoizedHelpers: - 'spec/utils/feed_discovery_spec.rb' - 'spec/utils/i18n_support_spec.rb' -# Offense count: 7 +# Offense count: 5 # Configuration parameters: EnforcedStyle, IgnoreSharedExamples. # SupportedStyles: always, named_only RSpec/NamedSubject: Exclude: - - 'spec/commands/fever_api/read_favicons_spec.rb' - 'spec/commands/fever_api/write_mark_item_spec.rb' # Offense count: 2 @@ -160,14 +198,13 @@ RSpec/NestedGroups: Exclude: - 'spec/integration/feed_importing_spec.rb' -# Offense count: 27 +# Offense count: 25 # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. RSpec/VerifiedDoubles: Exclude: - 'spec/commands/feed/create_spec.rb' - 'spec/commands/feed/fetch_one_spec.rb' - 'spec/commands/feed/find_new_stories_spec.rb' - - 'spec/commands/fever_api/write_mark_feed_spec.rb' - 'spec/repositories/story_repository_spec.rb' - 'spec/tasks/remove_old_stories_spec.rb' - 'spec/utils/feed_discovery_spec.rb' @@ -239,6 +276,12 @@ Rails/Validation: Exclude: - 'app/models/story.rb' +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Style/IfUnlessModifier: + Exclude: + - 'db/migrate/20240314031223_create_index_good_job_jobs_for_candidate_lookup.rb' + # Offense count: 1 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: EnforcedStyle. diff --git a/db/migrate/20240314031219_recreate_good_job_cron_indexes_with_conditional.rb b/db/migrate/20240314031219_recreate_good_job_cron_indexes_with_conditional.rb new file mode 100644 index 000000000..56cab35c3 --- /dev/null +++ b/db/migrate/20240314031219_recreate_good_job_cron_indexes_with_conditional.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +class RecreateGoodJobCronIndexesWithConditional < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + reversible do |dir| + dir.up do + unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_created_at_cond) + add_index :good_jobs, [:cron_key, :created_at], where: "(cron_key IS NOT NULL)", + name: :index_good_jobs_on_cron_key_and_created_at_cond, algorithm: :concurrently + end + unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_cron_at_cond) + add_index :good_jobs, [:cron_key, :cron_at], where: "(cron_key IS NOT NULL)", unique: true, + name: :index_good_jobs_on_cron_key_and_cron_at_cond, algorithm: :concurrently + end + + if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_created_at) + remove_index :good_jobs, name: :index_good_jobs_on_cron_key_and_created_at + end + if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_cron_at) + remove_index :good_jobs, name: :index_good_jobs_on_cron_key_and_cron_at + end + end + + dir.down do + unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_created_at) + add_index :good_jobs, [:cron_key, :created_at], + name: :index_good_jobs_on_cron_key_and_created_at, algorithm: :concurrently + end + unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_cron_at) + add_index :good_jobs, [:cron_key, :cron_at], unique: true, + name: :index_good_jobs_on_cron_key_and_cron_at, algorithm: :concurrently + end + + if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_created_at_cond) + remove_index :good_jobs, name: :index_good_jobs_on_cron_key_and_created_at_cond + end + if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_cron_at_cond) + remove_index :good_jobs, name: :index_good_jobs_on_cron_key_and_cron_at_cond + end + end + end + end +end diff --git a/db/migrate/20240314031220_create_good_job_labels.rb b/db/migrate/20240314031220_create_good_job_labels.rb new file mode 100644 index 000000000..1ba514e8b --- /dev/null +++ b/db/migrate/20240314031220_create_good_job_labels.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class CreateGoodJobLabels < 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_jobs, :labels) + end + end + + add_column :good_jobs, :labels, :text, array: true + end +end diff --git a/db/migrate/20240314031221_create_good_job_labels_index.rb b/db/migrate/20240314031221_create_good_job_labels_index.rb new file mode 100644 index 000000000..65dedd477 --- /dev/null +++ b/db/migrate/20240314031221_create_good_job_labels_index.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class CreateGoodJobLabelsIndex < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + reversible do |dir| + dir.up do + unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_labels) + add_index :good_jobs, :labels, using: :gin, where: "(labels IS NOT NULL)", + name: :index_good_jobs_on_labels, algorithm: :concurrently + end + end + + dir.down do + if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_labels) + remove_index :good_jobs, name: :index_good_jobs_on_labels + end + end + end + end +end diff --git a/db/migrate/20240314031222_remove_good_job_active_id_index.rb b/db/migrate/20240314031222_remove_good_job_active_id_index.rb new file mode 100644 index 000000000..8601f071a --- /dev/null +++ b/db/migrate/20240314031222_remove_good_job_active_id_index.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class RemoveGoodJobActiveIdIndex < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + reversible do |dir| + dir.up do + if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id) + remove_index :good_jobs, name: :index_good_jobs_on_active_job_id + end + end + + dir.down do + unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id) + add_index :good_jobs, :active_job_id, name: :index_good_jobs_on_active_job_id + end + end + end + end +end diff --git a/db/migrate/20240314031223_create_index_good_job_jobs_for_candidate_lookup.rb b/db/migrate/20240314031223_create_index_good_job_jobs_for_candidate_lookup.rb new file mode 100644 index 000000000..70e525626 --- /dev/null +++ b/db/migrate/20240314031223_create_index_good_job_jobs_for_candidate_lookup.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class CreateIndexGoodJobJobsForCandidateLookup < 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_name_exists?(:good_jobs, :index_good_job_jobs_for_candidate_lookup) + end + end + + add_index :good_jobs, [:priority, :created_at], order: { priority: "ASC NULLS LAST", created_at: :asc }, + where: "finished_at IS NULL", name: :index_good_job_jobs_for_candidate_lookup, + algorithm: :concurrently + end +end diff --git a/db/schema.rb b/db/schema.rb index 9de6816bf..3e7cab980 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: 2024_02_26_201050) do +ActiveRecord::Schema[7.1].define(version: 2024_03_14_031223) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -92,14 +92,16 @@ t.integer "executions_count" t.text "job_class" t.integer "error_event", limit: 2 + t.text "labels", array: true t.index ["active_job_id", "created_at"], name: "index_good_jobs_on_active_job_id_and_created_at" - t.index ["active_job_id"], name: "index_good_jobs_on_active_job_id" 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"], 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" - t.index ["cron_key", "cron_at"], name: "index_good_jobs_on_cron_key_and_cron_at", unique: true + 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 ["labels"], name: "index_good_jobs_on_labels", where: "(labels IS NOT NULL)", using: :gin + t.index ["priority", "created_at"], name: "index_good_job_jobs_for_candidate_lookup", where: "(finished_at IS NULL)" t.index ["priority", "created_at"], name: "index_good_jobs_jobs_on_priority_created_at_when_unfinished", order: { priority: "DESC NULLS LAST" }, where: "(finished_at IS NULL)" t.index ["queue_name", "scheduled_at"], name: "index_good_jobs_on_queue_name_and_scheduled_at", where: "(finished_at IS NULL)" t.index ["scheduled_at"], name: "index_good_jobs_on_scheduled_at", where: "(finished_at IS NULL)"