discourse/script/mwrap_sidekiq
Sam Saffron 28292d2759
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
2020-02-18 15:13:19 +11:00

145 lines
3.3 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# frozen_string_literal: true
if !ENV["LD_PRELOAD"]&.include?('mwrap')
# use malloc from libc that interacts better with mwrap
ENV['RAILS_ENV'] = 'production'
ENV["LD_PRELOAD"] = ""
ENV["MALLOC_ARENA_MAX"] = "2"
exec "mwrap #{__FILE__}"
end
require 'mwrap'
require 'webrick'
require File.expand_path("../../config/environment", __FILE__)
def render_table(array)
buffer = +""
width = array[0].map { |k| k.to_s.length }
cols = array[0].length
array.each do |row|
row.each_with_index do |val, i|
width[i] = [width[i].to_i, val.to_s.length].max
end
end
array[0].each_with_index do |col, i|
buffer << col.to_s.ljust(width[i], ' ')
if i == cols - 1
buffer << "\n"
else
buffer << ' | '
end
end
buffer << ("-" * (width.sum + width.length))
buffer << "\n"
array.drop(1).each do |row|
row.each_with_index do |val, i|
buffer << val.to_s.ljust(width[i], ' ')
if i == cols - 1
buffer << "\n"
else
buffer << ' | '
end
end
end
buffer
end
def rss
`ps -o rss= -p #{Process.pid}`.chomp.to_i
end
def mwrap_log
report = +""
Mwrap.quiet do
report << "Generation: #{GC.count} RSS kb: #{rss} Accounted Mem kb: #{(Mwrap.total_bytes_allocated - Mwrap.total_bytes_freed) / 1024}\n"
report << "Allocated bytes: #{Mwrap.total_bytes_allocated} Freed bytes: #{Mwrap.total_bytes_freed}\n"
stat = GC.stat
stat.each do |k, v|
report << "#{k}: #{v}\n"
end
report << "\n"
table = []
Mwrap.each(200) do |loc, total, allocations, frees, age_sum, max_life|
table << [total, allocations, frees, frees == 0 ? -1 : (age_sum / frees.to_f).round(2), max_life, loc]
end
table.sort! { |a, b| b[1] - b[2] <=> a[1] - a[2] }
table.prepend(["total", "allocations", "frees", "mean_life", "max_life", "location"])
report << render_table(table)
end
report
end
Thread.new do
begin
puts "Starting Logging Thread"
path = "/tmp/mwrap_#{Process.pid}"
`mkdir -p #{path}`
while true
log = mwrap_log
f = "#{path}/log_#{Time.now.strftime("%Y_%m_%d_%H%M%S")}"
File.write(f, log)
puts "Wrote #{f}"
sleep 60 * 60
end
rescue => e
STDERR.puts "ERROR crashed logger #{e}"
STDERR.puts e.backtrace
end
end
Thread.new do
puts "Starting WEBrick on port 9874"
server = WEBrick::HTTPServer.new(Port: 9874)
server.mount_proc '/' do |req, res|
res['ContentType'] = 'text/plain; charset=utf-8'
res.body = mwrap_log
res.status = 200
end
begin
server.start
rescue => e
STDERR.puts "Failed to start start server #{e}"
end
end
require 'sidekiq/cli'
begin
#Sidekiq::Logging.logger = nil
cli = Sidekiq::CLI.instance
options = ["-c", GlobalSetting.sidekiq_workers.to_s]
[['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"]
if !custom_queue_hostname || custom_queue_hostname.split(',').include?(Discourse.os_hostname)
options << "-q"
options << "#{queue_name},#{weight}"
end
end
cli.parse(options)
load Rails.root + "config/initializers/100-sidekiq.rb"
cli.run
rescue => e
STDERR.puts e.message
STDERR.puts e.backtrace.join("\n")
exit 1
end