From 2ff44747e6033c01c4524f2f242c689adc08f6c9 Mon Sep 17 00:00:00 2001 From: Lutz Lengemann Date: Wed, 26 Oct 2022 18:45:08 +0200 Subject: [PATCH] Fix natural sorting for processes (#5587) * Fix natural sorting for processes * Remove pry --- lib/sidekiq/web/helpers.rb | 18 ++++-------------- test/test_web_helpers.rb | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/sidekiq/web/helpers.rb b/lib/sidekiq/web/helpers.rb index 0f7f3618..cfaa46cb 100644 --- a/lib/sidekiq/web/helpers.rb +++ b/lib/sidekiq/web/helpers.rb @@ -148,25 +148,15 @@ module Sidekiq @processes ||= Sidekiq::ProcessSet.new end - # Sorts processes by hostname following the natural sort order so that - # 'worker.1' < 'worker.2' < 'worker.10' < 'worker.20' - # '2.1.1.1' < '192.168.0.2' < '192.168.0.10' + # Sorts processes by hostname following the natural sort order def sorted_processes @sorted_processes ||= begin return processes unless processes.all? { |p| p["hostname"] } - split_characters = /[._-]+/ - - padding = processes.flat_map { |p| p["hostname"].split(split_characters) }.map(&:size).max - processes.to_a.sort_by do |process| - process["hostname"].split(split_characters).map do |substring| - # Left-pad the substring with '0' if it starts with a number or 'a' - # otherwise, so that '25' < 192' < 'a' ('025' < '192' < 'aaa') - padding_char = substring[0].match?(/\d/) ? "0" : "a" - - substring.rjust(padding, padding_char) - end + # Kudos to `shurikk` on StackOverflow + # https://stackoverflow.com/a/15170063/575547 + process["hostname"].split(/(\d+)/).map { |a| /\d+/.match?(a) ? a.to_i : a } end end end diff --git a/test/test_web_helpers.rb b/test/test_web_helpers.rb index d1ba1b90..d232769e 100644 --- a/test/test_web_helpers.rb +++ b/test/test_web_helpers.rb @@ -146,4 +146,21 @@ describe "Web helpers" do assert obj.sorted_processes.all? { |process| assert_instance_of Sidekiq::Process, process } assert_equal ["2.1.1.1", "192.168.0.2", "192.168.0.10", "a.1", "a.2", "a.10.1", "a.10.2", "a.23", "busybee-2__34", "busybee--10_1"], obj.sorted_processes.map { |process| process["hostname"] } end + + it "sorts processes with multiple dividers correctly" do + ["worker_critical.2", "worker_default.1", "worker_critical.1", "worker_default.2", "worker_critical.10"].each do |hostname| + pdata = {"hostname" => hostname, "pid" => "123", "started_at" => Time.now.to_i} + key = "#{hostname}:123" + + Sidekiq.redis do |conn| + conn.sadd("processes", [key]) + conn.hmset(key, "info", Sidekiq.dump_json(pdata), "busy", 0, "beat", Time.now.to_f) + end + end + + obj = Helpers.new + + assert obj.sorted_processes.all? { |process| assert_instance_of Sidekiq::Process, process } + assert_equal ["worker_critical.1", "worker_critical.2", "worker_critical.10", "worker_default.1", "worker_default.2"], obj.sorted_processes.map { |process| process["hostname"] } + end end