Module: Legion::Region::Failover

Defined in:
lib/legion/region/failover.rb

Defined Under Namespace

Classes: LagTooHighError, UnknownRegionError

Constant Summary collapse

MAX_LAG_SECONDS =
30

Class Method Summary collapse

Class Method Details

.promote!(region:) ⇒ Object

Raises:



10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/legion/region/failover.rb', line 10

def promote!(region:)
  validate_target!(region)

  lag = replication_lag
  raise LagTooHighError, "replication lag #{lag.round(1)}s exceeds #{MAX_LAG_SECONDS}s threshold" if lag && lag > MAX_LAG_SECONDS

  previous = Legion::Settings.dig(:region, :primary)
  Legion::Settings[:region][:primary] = region
  Legion::Events.emit('region.failover', from: previous, to: region) if defined?(Legion::Events)

  { promoted: region, previous: previous, lag_seconds: lag }
end

.replication_lagObject



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/legion/region/failover.rb', line 23

def replication_lag
  return nil unless defined?(Legion::Data) && Legion::Data.respond_to?(:connection) && Legion::Data.connection

  row = Legion::Data.connection.fetch(
    'SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp())) AS lag'
  ).first
  row[:lag]&.to_f
rescue StandardError => e
  Legion::Logging.debug "Region::Failover#replication_lag failed: #{e.message}" if defined?(Legion::Logging)
  nil
end

.validate_target!(region) ⇒ Object

Raises:



35
36
37
38
39
40
41
42
43
# File 'lib/legion/region/failover.rb', line 35

def validate_target!(region)
  peers = Legion::Settings.dig(:region, :peers) || []
  failover = Legion::Settings.dig(:region, :failover)
  known = (peers + [failover].compact).uniq

  return if known.include?(region)

  raise UnknownRegionError, "'#{region}' is not a known peer or failover region (known: #{known.join(', ')})"
end