Module: ResilientReads::LagChecker
- Defined in:
- lib/resilient_reads/lag_checker.rb
Class Method Summary collapse
-
.lag_for(replica) ⇒ Object
Returns the replication lag in seconds for a replica.
- .lag_for_mysql(conn) ⇒ Object
- .lag_for_postgresql(conn) ⇒ Object
-
.replication_lag ⇒ Object
Convenience: check replication lag using the default reading connection.
Class Method Details
.lag_for(replica) ⇒ Object
Returns the replication lag in seconds for a replica. Supports PostgreSQL and MySQL/MariaDB. Returns 0 when the replica is fully caught up, nil on error.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/resilient_reads/lag_checker.rb', line 6 def self.lag_for(replica) conn = replica.connection adapter_name = conn.adapter_name.downcase if adapter_name.include?("postgresql") lag_for_postgresql(conn) elsif adapter_name.include?("mysql") || adapter_name.include?("trilogy") lag_for_mysql(conn) else ResilientReads.log(:debug, "Lag check not supported for adapter '#{adapter_name}'") nil end rescue => e ResilientReads.log(:debug, "Lag check failed for '#{replica.name}': #{e.}") nil ensure replica.release_connection rescue nil end |
.lag_for_mysql(conn) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/resilient_reads/lag_checker.rb', line 47 def self.lag_for_mysql(conn) # Prefer SHOW REPLICA STATUS (MySQL 8.0.22+, MariaDB 10.5.1+) # and fall back to the deprecated SHOW SLAVE STATUS. result = begin conn.execute("SHOW REPLICA STATUS") rescue ActiveRecord::StatementInvalid conn.execute("SHOW SLAVE STATUS") end row = if result.respond_to?(:first) result.first elsif result.respond_to?(:to_a) result.to_a.first end return nil unless row # Seconds_Behind_Source (MySQL 8.0.22+) / Seconds_Behind_Master (legacy) lag = if row.is_a?(Hash) row["Seconds_Behind_Source"] || row["Seconds_Behind_Master"] elsif row.respond_to?(:[]) row["Seconds_Behind_Source"] || row["Seconds_Behind_Master"] end lag&.to_f rescue => e ResilientReads.log(:debug, "MySQL lag check failed: #{e.}") nil end |
.lag_for_postgresql(conn) ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/resilient_reads/lag_checker.rb', line 35 def self.lag_for_postgresql(conn) result = conn.execute(<<~SQL) SELECT CASE WHEN pg_last_wal_receive_lsn() IS NULL THEN NULL WHEN pg_last_wal_receive_lsn() = pg_last_wal_replay_lsn() THEN 0 ELSE EXTRACT(EPOCH FROM now() - pg_last_xact_replay_timestamp())::float END AS lag SQL lag = result.first&.fetch("lag", nil) lag&.to_f end |
.replication_lag ⇒ Object
Convenience: check replication lag using the default reading connection.
26 27 28 29 30 31 |
# File 'lib/resilient_reads/lag_checker.rb', line 26 def self.replication_lag replica = ResilientReads.replica_pool.next_healthy return nil unless replica lag_for(replica) end |