Skip to content

Commit

Permalink
Fix natural sorting for processes (#5587)
Browse files Browse the repository at this point in the history
* Fix natural sorting for processes

* Remove pry
  • Loading branch information
mobilutz authored and mperham committed Oct 26, 2022
1 parent 0588caf commit 2ff4474
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 14 deletions.
18 changes: 4 additions & 14 deletions lib/sidekiq/web/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,25 +148,15 @@ def processes
@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
Expand Down
17 changes: 17 additions & 0 deletions test/test_web_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,21 @@ def params
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

0 comments on commit 2ff4474

Please sign in to comment.