Class: Pgbus::Generators::MigrationDetector

Inherits:
Object
  • Object
show all
Defined in:
lib/pgbus/generators/migration_detector.rb

Overview

Inspects a live ActiveRecord connection and determines which of pgbus’s migration generators need to run to bring the schema up to date.

Usage:

detector = Pgbus::Generators::MigrationDetector.new(connection)
detector.missing_migrations
# => [:add_uniqueness_keys, :add_job_stats_queue_index, ...]

The returned symbols correspond to generator names that the pgbus:update generator invokes via Thor composition. Each symbol maps to exactly one generator (see GENERATOR_MAP).

Detection rules:

  1. Fresh install (no core tables) → returns [:fresh_install] as a sentinel. The caller should tell the user to run pgbus:install instead of stacking 8 migrations.

  2. Core tables missing → queued unconditionally. These are features pgbus assumes are present.

  3. Opt-in feature tables missing → queued unconditionally. The user asked for update-to-latest, so we add the migration files but don’t enable the feature in config. They’ll opt in separately.

  4. Columns missing on existing tables → queued. These are in-place schema upgrades (e.g. add_job_stats_latency adds enqueue_latency_ms + retry_count).

  5. Indexes missing on existing tables → queued. Additive, safe.

  6. Modern replacements for legacy tables (e.g. pgbus_job_locks →pgbus_uniqueness_keys) → queue the migration path only if the legacy table still exists. Otherwise queue the fresh install.

Constant Summary collapse

FRESH_INSTALL =

Sentinel returned when the database looks empty of pgbus tables. The caller (pgbus:update generator) should redirect the user to pgbus:install rather than trying to stack the full schema as individual add_* migrations.

:fresh_install
CORE_INSTALL_TABLES =

The set of tables that the base pgbus:install migration creates. If NONE of these exist, we treat the DB as a fresh install.

%w[
  pgbus_processed_events
  pgbus_processes
  pgbus_failed_events
  pgbus_semaphores
  pgbus_blocked_executions
  pgbus_batches
].freeze
GENERATOR_MAP =

generator_key → Rails generator name. Passed to Thor’s invoke.

Note: uniqueness_keys uses the migrate_job_locks generator for both the fresh-install and upgrade-from-job_locks paths. The template is idempotent: ‘unless table_exists?(:pgbus_uniqueness_keys)` creates it, and `if table_exists?(:pgbus_job_locks)` drops the legacy table. One generator covers both cases.

{
  uniqueness_keys: "pgbus:migrate_job_locks",
  add_job_stats: "pgbus:add_job_stats",
  add_job_stats_latency: "pgbus:add_job_stats_latency",
  add_job_stats_queue_index: "pgbus:add_job_stats_queue_index",
  add_stream_stats: "pgbus:add_stream_stats",
  add_presence: "pgbus:add_presence",
  add_queue_states: "pgbus:add_queue_states",
  add_outbox: "pgbus:add_outbox",
  add_recurring: "pgbus:add_recurring",
  add_failed_events_index: "pgbus:add_failed_events_index",
  tune_autovacuum: "pgbus:tune_autovacuum"
}.freeze
DESCRIPTIONS =

Human-friendly description of each migration for the generator output. Keeps the update generator’s run log readable.

{
  uniqueness_keys: "uniqueness keys table (job deduplication, also upgrades legacy job_locks if present)",
  add_job_stats: "job stats table (Insights dashboard)",
  add_job_stats_latency: "job stats latency columns (enqueue_latency_ms, retry_count)",
  add_job_stats_queue_index: "job stats (queue_name, created_at) index",
  add_stream_stats: "stream stats table (opt-in real-time Insights)",
  add_presence: "presence members table (Turbo Streams presence)",
  add_queue_states: "queue states table (pause/resume)",
  add_outbox: "outbox entries table (transactional outbox)",
  add_recurring: "recurring tasks + executions tables",
  add_failed_events_index: "unique index on pgbus_failed_events (queue_name, msg_id)",
  tune_autovacuum: "autovacuum tuning for PGMQ queue and archive tables"
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(connection) ⇒ MigrationDetector

Returns a new instance of MigrationDetector.



96
97
98
# File 'lib/pgbus/generators/migration_detector.rb', line 96

def initialize(connection)
  @connection = connection
end

Instance Method Details

#missing_migrationsObject

Returns an Array of generator keys (symbols) in the order they should run. Dependencies are resolved implicitly via order: the base table creation for a feature always comes before the column/index add-ons.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/pgbus/generators/migration_detector.rb', line 104

def missing_migrations
  return [FRESH_INSTALL] if fresh_install?

  [
    *uniqueness_key_migrations,
    *job_stats_migrations,
    *stream_stats_migrations,
    *presence_migrations,
    *queue_states_migrations,
    *outbox_migrations,
    *recurring_migrations,
    *failed_events_index_migrations,
    *autovacuum_migrations
  ]
end