DEV(cache_critical_dns): add caching for MessageBus Redis hostname

We are already caching any DB_HOST and REDIS_HOST (and their
accompanying replicas), we should also cache the resolved addresses for
the MessageBus specific Redis. This is a noop if no MB redis is defined
in config. A side effect is that the MB will also support SRV lookup and
priorities, following the same convention as the other cached services.

The port argument was added to redis_healthcheck so that the script
supports a setup where Redis is running on a non-default port.

Did some minor refactoring to improve readability when filtering out the
CRITICAL_HOST_ENV_VARS. The `select` block was a bit confusing, so the
sequence was made easier to follow.

We were coercing an environment variable to an int in a few places, so
the `env_as_int` method was introduced to do that coercion in one place and
for convenience purposes default to a value if provided.

See /t/68301/30.
This commit is contained in:
Michael Fitz-Payne 2022-10-06 16:11:24 +10:00 committed by Michael Fitz-Payne
parent 6888eb5c2d
commit 5fdbbe3045

View File

@ -86,9 +86,12 @@ CRITICAL_HOST_ENV_VARS = %w{
DISCOURSE_REDIS_HOST
DISCOURSE_REDIS_SLAVE_HOST
DISCOURSE_REDIS_REPLICA_HOST
DISCOURSE_MESSAGE_BUS_REDIS_HOST
DISCOURSE_MESSAGE_BUS_REDIS_REPLICA_HOST
}
DEFAULT_DB_NAME = "discourse"
DEFAULT_REDIS_PORT = 6379
HOST_RESOLVER_CACHE = {}
HOST_HEALTHY_CACHE = {}
@ -203,10 +206,11 @@ class HealthyCache
end
end
def redis_healthcheck(host:, password:)
def redis_healthcheck(host:, password:, port: DEFAULT_REDIS_PORT)
client_opts = {
host: host,
password: password,
port: port,
timeout: 1,
}
if !nilempty(ENV['DISCOURSE_REDIS_USE_SSL']).nil? then
@ -260,6 +264,16 @@ HEALTH_CHECKS = {
redis_healthcheck(
host: addr,
password: ENV["DISCOURSE_REDIS_PASSWORD"])},
"DISCOURSE_MESSAGE_BUS_REDIS_HOST": lambda { |addr|
redis_healthcheck(
host: addr,
port: env_as_int("DISCOURSE_MESSAGE_BUS_REDIS_PORT", DEFAULT_REDIS_PORT),
password: ENV["DISCOURSE_MESSAGE_BUS_REDIS_PASSWORD"])},
"DISCOURSE_MESSAGE_BUS_REDIS_REPLICA_HOST": lambda { |addr|
redis_healthcheck(
host: addr,
port: env_as_int("DISCOURSE_MESSAGE_BUS_REDIS_REPLICA_PORT", DEFAULT_REDIS_PORT),
password: ENV["DISCOURSE_MESSAGE_BUS_REDIS_PASSWORD"])},
}
def log(msg)
@ -292,7 +306,7 @@ end
def send_counter(name, description, labels, value)
host = "localhost"
port = ENV.fetch("DISCOURSE_PROMETHEUS_COLLECTOR_PORT", 9405).to_i
port = env_as_int("DISCOURSE_PROMETHEUS_COLLECTOR_PORT", 9405)
if labels
labels = labels.map do |k, v|
@ -362,6 +376,14 @@ def env_srv_name(env_name)
nilempty(ENV[env_srv_var(env_name)])
end
def env_as_int(env_name, default = nil)
val = ENV.fetch(env_name, default)
if nilempty(val).nil?
return val
end
val.to_i
end
def run_and_report(hostname_vars)
errors = run(hostname_vars)
if errors.empty?
@ -428,23 +450,28 @@ end
# If any of the host variables are an explicit IP we will not attempt to cache
# them.
all_hostname_vars = CRITICAL_HOST_ENV_VARS.select do |name|
begin
host = ENV[name]
next if nilempty(host).nil?
if nilempty(host).nil?
# don't attempt to cache host vars that aren't present in the environment
false
else
begin
IPAddr.new(host)
# host is an IPv4 / IPv6 address
false
rescue IPAddr::InvalidAddressError, IPAddr::AddressFamilyError
true
end
end
end
# Populate the SRV_PRIORITY_FILTERS for any name that has a priority present in
# the environment. If no priority thresholds are found for the name, the default
# is that no filtering based on priority will be performed.
CRITICAL_HOST_ENV_VARS.each do |v|
if (name = env_srv_name(v))
max = ENV.fetch("#{env_srv_var(v)}_PRIORITY_LE", SRV_PRIORITY_THRESHOLD_MAX).to_i
min = ENV.fetch("#{env_srv_var(v)}_PRIORITY_GE", SRV_PRIORITY_THRESHOLD_MIN).to_i
max = env_as_int("#{env_srv_var(v)}_PRIORITY_LE", SRV_PRIORITY_THRESHOLD_MAX)
min = env_as_int("#{env_srv_var(v)}_PRIORITY_GE", SRV_PRIORITY_THRESHOLD_MIN)
if max > SRV_PRIORITY_THRESHOLD_MAX ||
min < SRV_PRIORITY_THRESHOLD_MIN ||
min > max