Class: Gitlab::Database::LoadBalancing::ServiceDiscovery::Sampler

Inherits:
Object
  • Object
show all
Defined in:
lib/gitlab/database/load_balancing/service_discovery/sampler.rb

Instance Method Summary collapse

Constructor Details

#initialize(max_replica_pools:, seed: Random.new_seed) ⇒ Sampler

Returns a new instance of Sampler.



8
9
10
11
12
13
14
# File 'lib/gitlab/database/load_balancing/service_discovery/sampler.rb', line 8

def initialize(max_replica_pools:, seed: Random.new_seed)
  # seed must be set once and consistent
  # for every invocation of #sample on
  # the same instance of Sampler
  @seed = seed
  @max_replica_pools = max_replica_pools
end

Instance Method Details

#sample(addresses) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/gitlab/database/load_balancing/service_discovery/sampler.rb', line 16

def sample(addresses)
  return addresses if @max_replica_pools.nil? || addresses.count <= @max_replica_pools

  ::Gitlab::Database::LoadBalancing::Logger.debug(
    event: :host_list_limit_exceeded,
    message: "Host list length exceeds max_replica_pools so random hosts will be chosen.",
    max_replica_pools: @max_replica_pools,
    total_host_list_length: addresses.count,
    randomization_seed: @seed
  )

  # First sort them in case the ordering from DNS server changes
  # then randomly order all addresses using consistent seed so
  # this process always gives the same set for this instance of
  # Sampler
  addresses = addresses.sort
  addresses = addresses.shuffle(random: Random.new(@seed))

  # Group by hostname so that we can sample evenly across hosts
  addresses_by_host = addresses.group_by(&:hostname)

  selected_addresses = []
  while selected_addresses.count < @max_replica_pools
    # Loop over all hostnames grabbing one address at a time to
    # evenly distribute across all hostnames
    addresses_by_host.each do |host, addresses|
      next if addresses.empty?

      selected_addresses << addresses.pop

      break unless selected_addresses.count < @max_replica_pools
    end
  end

  selected_addresses
end