Class: ForestAdminAgent::AuditTrail::Sql::Migrator

Inherits:
Object
  • Object
show all
Defined in:
lib/forest_admin_agent/audit_trail/sql/migrator.rb

Overview

Applies ForestAdminAgent::AuditTrail::Sql::Migrations::ALL to the audit table, tracking what has run in a companion table named after it — audit_logs_migration beside audit_logs (both namespaced in the forest schema on Postgres). One tracker per audited table, so two stores configured with different table_names each get their own schema history instead of reading each other's as done.

On Postgres the migrations run inside a transaction-scoped advisory lock, so several agent instances booting at once apply them one after another instead of racing on the same DDL. The schema is created (and committed) first, made idempotent (CREATE SCHEMA IF NOT EXISTS + tolerating a concurrent create), because the lock cannot cover a not-yet-existing schema.

Constant Summary collapse

ADVISORY_LOCK =

Arbitrary but stable key pair identifying the audit-trail migration critical section.

[0x464f, 0x5254].freeze
DUPLICATE_SCHEMA_STATES =

duplicate_schema, and the unique violation on pg_namespace the same race can raise instead.

%w[42P06 23505].freeze

Instance Method Summary collapse

Constructor Details

#initialize(connection, schema:, table_name:) ⇒ Migrator

Returns a new instance of Migrator.



19
20
21
22
23
# File 'lib/forest_admin_agent/audit_trail/sql/migrator.rb', line 19

def initialize(connection, schema:, table_name:)
  @connection = connection
  @schema = schema # nil on adapters without schema support
  @table_name = table_name
end

Instance Method Details

#runObject



25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/forest_admin_agent/audit_trail/sql/migrator.rb', line 25

def run
  ensure_schema

  if postgres?
    @connection.transaction do
      @connection.execute("SELECT pg_advisory_xact_lock(#{ADVISORY_LOCK[0]}, #{ADVISORY_LOCK[1]})")
      apply_pending
    end
  else
    apply_pending
  end
end