PERF: avoid shelling to get hostname aggressively

Previously we had many places in the app that called `hostname` to get
hostname of a server. This commit replaces the pattern in 2 ways

1. We cache the result in `Discourse.os_hostname` so it is only ever called once

2. We prefer to use Socket.gethostname which avoids making a shell command

This improves performance as we are not spawning hostname processes throughout
the app lifetime
This commit is contained in:
Sam Saffron 2020-02-18 15:11:30 +11:00
parent cfd56e9159
commit 28292d2759
No known key found for this signature in database
GPG Key ID: B9606168D2FFD9F5
9 changed files with 26 additions and 8 deletions

View File

@ -40,7 +40,7 @@ module Jobs
self.class.mutex.synchronize do self.class.mutex.synchronize do
@data = {} @data = {}
@data["hostname"] = `hostname`.strip # Hostname @data["hostname"] = Discourse.os_hostname
@data["pid"] = Process.pid # Pid @data["pid"] = Process.pid # Pid
@data["database"] = db # DB name - multisite db name it ran on @data["database"] = db # DB name - multisite db name it ran on
@data["job_id"] = jid # Job unique ID @data["job_id"] = jid # Job unique ID

View File

@ -9,7 +9,7 @@ class OptimizedImage < ActiveRecord::Base
URL_REGEX ||= /(\/optimized\/\dX[\/\.\w]*\/([a-zA-Z0-9]+)[\.\w]*)/ URL_REGEX ||= /(\/optimized\/\dX[\/\.\w]*\/([a-zA-Z0-9]+)[\.\w]*)/
def self.lock(upload_id, width, height) def self.lock(upload_id, width, height)
@hostname ||= `hostname`.strip rescue "unknown" @hostname ||= Discourse.os_hostname
# note, the extra lock here ensures we only optimize one image per machine on webs # note, the extra lock here ensures we only optimize one image per machine on webs
# this can very easily lead to runaway CPU so slowing it down is beneficial and it is hijacked # this can very easily lead to runaway CPU so slowing it down is beneficial and it is hijacked
# #

View File

@ -69,7 +69,7 @@ if Sidekiq.server?
Rails.application.config.after_initialize do Rails.application.config.after_initialize do
scheduler_hostname = ENV["UNICORN_SCHEDULER_HOSTNAME"] scheduler_hostname = ENV["UNICORN_SCHEDULER_HOSTNAME"]
if !scheduler_hostname || scheduler_hostname.split(',').include?(`hostname`.strip) if !scheduler_hostname || scheduler_hostname.split(',').include?(Discourse.os_hostname)
MiniScheduler.start(workers: GlobalSetting.mini_scheduler_workers) MiniScheduler.start(workers: GlobalSetting.mini_scheduler_workers)
end end
end end

View File

@ -39,7 +39,7 @@ class Demon::Sidekiq < ::Demon::Base
[['critical', 8], ['default', 4], ['low', 2], ['ultra_low', 1]].each do |queue_name, weight| [['critical', 8], ['default', 4], ['low', 2], ['ultra_low', 1]].each do |queue_name, weight|
custom_queue_hostname = ENV["UNICORN_SIDEKIQ_#{queue_name.upcase}_QUEUE_HOSTNAME"] custom_queue_hostname = ENV["UNICORN_SIDEKIQ_#{queue_name.upcase}_QUEUE_HOSTNAME"]
if !custom_queue_hostname || custom_queue_hostname.split(',').include?(`hostname`.strip) if !custom_queue_hostname || custom_queue_hostname.split(',').include?(Discourse.os_hostname)
options << "-q" options << "-q"
options << "#{queue_name},#{weight}" options << "#{queue_name},#{weight}"
end end

View File

@ -312,6 +312,24 @@ module Discourse
end end
end end
# hostname of the server, operating system level
# called os_hostname so we do no confuse it with current_hostname
def self.os_hostname
@os_hostname ||=
begin
require 'socket'
Socket.gethostname
rescue => e
warn_exception(e, message: 'Socket.gethostname is not working')
begin
`hostname`.strip
rescue => e
warn_exception(e, message: 'hostname command is not working')
'unknown_host'
end
end
end
# Get the current base URL for the current site # Get the current base URL for the current site
def self.current_hostname def self.current_hostname
SiteSetting.force_hostname.presence || RailsMultisite::ConnectionManagement.current_hostname SiteSetting.force_hostname.presence || RailsMultisite::ConnectionManagement.current_hostname

View File

@ -8,7 +8,7 @@ class DiscourseLogstashLogger
uri: uri, uri: uri,
sync: true, sync: true,
customize_event: ->(event) { customize_event: ->(event) {
event['hostname'] = `hostname`.chomp event['hostname'] = Discourse.os_hostname
event['severity_name'] = event['severity'] event['severity_name'] = event['severity']
event['severity'] = Object.const_get("Logger::Severity::#{event['severity']}") event['severity'] = Object.const_get("Logger::Severity::#{event['severity']}")
event['type'] = type event['type'] = type

View File

@ -31,7 +31,7 @@ module FreedomPatches
) )
SQL SQL
hostname = `hostname` rescue "" hostname = Discourse.os_hostname
sql = ActiveRecord::Base.public_send(:sanitize_sql_array, [sql, { sql = ActiveRecord::Base.public_send(:sanitize_sql_array, [sql, {
version: version || "", version: version || "",
duration: (time.real * 1000).to_i, duration: (time.real * 1000).to_i,

View File

@ -5,7 +5,7 @@ class MessageBusDiags
@host_info = {} @host_info = {}
def self.my_id def self.my_id
@my_id ||= "#{`hostname`}-#{Process.pid}" @my_id ||= "#{Discourse.os_hostname}-#{Process.pid}"
end end
def self.seen_host(name) def self.seen_host(name)

View File

@ -128,7 +128,7 @@ begin
[['critical', 8], ['default', 4], ['low', 2], ['ultra_low', 1]].each do |queue_name, weight| [['critical', 8], ['default', 4], ['low', 2], ['ultra_low', 1]].each do |queue_name, weight|
custom_queue_hostname = ENV["UNICORN_SIDEKIQ_#{queue_name.upcase}_QUEUE_HOSTNAME"] custom_queue_hostname = ENV["UNICORN_SIDEKIQ_#{queue_name.upcase}_QUEUE_HOSTNAME"]
if !custom_queue_hostname || custom_queue_hostname.split(',').include?(`hostname`.strip) if !custom_queue_hostname || custom_queue_hostname.split(',').include?(Discourse.os_hostname)
options << "-q" options << "-q"
options << "#{queue_name},#{weight}" options << "#{queue_name},#{weight}"
end end