summaryrefslogtreecommitdiff
path: root/app/models/postgresql/replication_slot.rb
blob: 70c7432e6b59b57e95849ac6767d6984a0ab6717 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# frozen_string_literal: true

module Postgresql
  class ReplicationSlot < ActiveRecord::Base
    self.table_name = 'pg_replication_slots'

    # Returns true if the lag observed across all replication slots exceeds a
    # given threshold.
    #
    # max - The maximum replication lag size, in bytes. Based on GitLab.com
    #       statistics it takes between 1 and 5 seconds to replicate around
    #       100 MB of data.
    def self.lag_too_great?(max = 100.megabytes)
      lag_function = "#{Gitlab::Database.pg_wal_lsn_diff}" \
        "(#{Gitlab::Database.pg_current_wal_insert_lsn}(), restart_lsn)::bigint"

      # We force the use of a transaction here so the query always goes to the
      # primary, even when using the EE DB load balancer.
      sizes = transaction { pluck(lag_function) }
      too_great = sizes.count { |size| size >= max }

      # If too many replicas are falling behind too much, the availability of a
      # GitLab instance might suffer. To prevent this from happening we require
      # at least 1 replica to have data recent enough.
      if sizes.any? && too_great.positive?
        (sizes.length - too_great) <= 1
      else
        false
      end
    end
  end
end