From 3b5ae30c4e5e9e760268243ab5c14664a2f8d236 Mon Sep 17 00:00:00 2001 From: Mike Perham Date: Wed, 14 Oct 2020 15:09:50 -0700 Subject: [PATCH] Add process RSS to the Busy page, fixes #4717 --- Changes.md | 5 +++++ lib/sidekiq/api.rb | 9 ++++++--- lib/sidekiq/launcher.rb | 27 +++++++++++++++++++++++++- lib/sidekiq/web/helpers.rb | 12 ++++++++++++ test/test_launcher.rb | 8 ++++++++ web/assets/stylesheets/application.css | 12 ++++++++++++ web/views/busy.erb | 2 ++ 7 files changed, 71 insertions(+), 4 deletions(-) diff --git a/Changes.md b/Changes.md index 1190e378..5f2e5838 100644 --- a/Changes.md +++ b/Changes.md @@ -2,6 +2,11 @@ [Sidekiq Changes](https://github.com/mperham/sidekiq/blob/master/Changes.md) | [Sidekiq Pro Changes](https://github.com/mperham/sidekiq/blob/master/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/mperham/sidekiq/blob/master/Ent-Changes.md) +HEAD +--------- + +- Add process RSS on the Busy page [#4717] + 6.1.2 --------- diff --git a/lib/sidekiq/api.rb b/lib/sidekiq/api.rb index fdc7c62b..5f19e60f 100644 --- a/lib/sidekiq/api.rb +++ b/lib/sidekiq/api.rb @@ -791,19 +791,22 @@ module Sidekiq # you'll be happier this way conn.pipelined do procs.each do |key| - conn.hmget(key, "info", "busy", "beat", "quiet") + conn.hmget(key, "info", "busy", "beat", "quiet", "rss") end end } - result.each do |info, busy, at_s, quiet| + result.each do |info, busy, at_s, quiet, rss| # If a process is stopped between when we query Redis for `procs` and # when we query for `result`, we will have an item in `result` that is # composed of `nil` values. next if info.nil? hash = Sidekiq.load_json(info) - yield Process.new(hash.merge("busy" => busy.to_i, "beat" => at_s.to_f, "quiet" => quiet)) + yield Process.new(hash.merge("busy" => busy.to_i, + "beat" => at_s.to_f, + "quiet" => quiet, + "rss" => rss)) end end diff --git a/lib/sidekiq/launcher.rb b/lib/sidekiq/launcher.rb index 644c16f6..95854bbd 100644 --- a/lib/sidekiq/launcher.rb +++ b/lib/sidekiq/launcher.rb @@ -154,12 +154,17 @@ module Sidekiq end fails = procd = 0 + kb = memory_usage(::Process.pid) _, exists, _, _, msg = Sidekiq.redis { |conn| conn.multi { conn.sadd("processes", key) conn.exists?(key) - conn.hmset(key, "info", to_json, "busy", curstate.size, "beat", Time.now.to_f, "quiet", @done) + conn.hmset(key, "info", to_json, + "busy", curstate.size, + "beat", Time.now.to_f, + "quiet", @done, + "rss", kb) conn.expire(key, 60) conn.rpop("#{key}-signals") } @@ -180,6 +185,26 @@ module Sidekiq end end + MEMORY_GRABBER = case RUBY_PLATFORM + when /linux/ + ->(pid) { + IO.readlines("/proc/#{$$}/status").each do |line| + next unless line.start_with?("VmRSS:") + break line.split[1].to_i + end + } + when /darwin|bsd/ + ->(pid) { + `ps -o pid,rss -p #{pid}`.lines.last.split.last.to_i + } + else + ->(pid) { 0 } + end + + def memory_usage(pid) + MEMORY_GRABBER.call(pid) + end + def to_data @data ||= begin { diff --git a/lib/sidekiq/web/helpers.rb b/lib/sidekiq/web/helpers.rb index f845d724..71a279bc 100644 --- a/lib/sidekiq/web/helpers.rb +++ b/lib/sidekiq/web/helpers.rb @@ -258,7 +258,19 @@ module Sidekiq end end + def format_memory(rss_kb) + return "" if rss_kb.nil? || rss_kb == 0 + + if rss_kb < 100_000 + "#{number_with_delimiter(rss_kb)} KB" + else + "#{number_with_delimiter((rss_kb / 1024.0).to_i)} MB" + end + end + def number_with_delimiter(number) + return "" if number.nil? + begin Float(number) rescue ArgumentError, TypeError diff --git a/test/test_launcher.rb b/test/test_launcher.rb index 96e2e80d..4d0c740d 100644 --- a/test/test_launcher.rb +++ b/test/test_launcher.rb @@ -13,6 +13,14 @@ describe Sidekiq::Launcher do Sidekiq::Manager.new(opts) end + describe 'memory collection' do + it 'works in any test environment' do + kb = Sidekiq::Launcher::MEMORY_GRABBER.call($$) + refute_nil kb + assert kb > 0 + end + end + describe 'heartbeat' do before do @mgr = new_manager(options) diff --git a/web/assets/stylesheets/application.css b/web/assets/stylesheets/application.css index 9df3c69d..da900408 100644 --- a/web/assets/stylesheets/application.css +++ b/web/assets/stylesheets/application.css @@ -1152,3 +1152,15 @@ div.interval-slider input { .delete-confirm { width: 20%; } + +.circled { + border-color: #333; + color: #eee; + background-color: #b1003e; + border-radius: 50%; + text-align: center; + vertical-align: middle; + padding: 3px 7px; + font-size: 0.7em; + margin-left: 5px; +} diff --git a/web/views/busy.erb b/web/views/busy.erb index e6abd8b0..ea89987d 100644 --- a/web/views/busy.erb +++ b/web/views/busy.erb @@ -18,6 +18,7 @@ <%= t('Name') %> <%= t('Started') %> + <%= t('RSS') %>? <%= t('Threads') %> <%= t('Busy') %>   @@ -42,6 +43,7 @@ <%= process['queues'] * ", " %> <%= relative_time(Time.at(process['started_at'])) %> + <%= format_memory(process['rss'].to_i) %> <%= process['concurrency'] %> <%= process['busy'] %>