sidekiq-err 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 540a25393182c06c16aa1133a3eb97a382a4e7918d37564ab48ea1f5244b3bad
4
+ data.tar.gz: 1780bcba830dc7332e999381ade9e86f0480d4386727aef14f7f680ea1e0efd6
5
+ SHA512:
6
+ metadata.gz: 0d40784c25269602e7b9698583f27a0cc0a6c760693bc0947a5a816789b4a29ee79dc16fe6d5e8598a5efd090e84aba1123c3ea5080681664a9e76e7469d5418
7
+ data.tar.gz: 12b25794cdb14be82e0a048037596d897764f3b56bb2b875904cd8909c1266f67f9475725fbecae9bf2ca7bf0aa4d584fcc9caa06c6c30b78cddba74f033cd6a
data/exe/sidekiq-err ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'sidekiq-err'
6
+
7
+ require 'pry' if ENV.fetch('USE_PRY', false)
8
+
9
+ # main entry point
10
+ begin
11
+ case ARGV[0]
12
+ when '-a', '--alive'
13
+ SidekiqErr.alive?
14
+ when '-r', '--report'
15
+ SidekiqErr.status(ARGV[1])
16
+ when '-h', '--help'
17
+ SidekiqErr.print_usage
18
+ else
19
+ puts
20
+ puts 'Uknown command, use --help for usage details'
21
+ puts
22
+ end
23
+ rescue SidekiqErr::Error, Redis::CannotConnectError, Redis::TimeoutError => e
24
+ puts "Error: #{e.message}"
25
+ puts
26
+ exit(1)
27
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqErr
4
+ class Alive
5
+ def self.check?
6
+ process_set = Sidekiq::ProcessSet.new
7
+ raise(NoProcessFound, 'No sidekiq process running!') if process_set.size.zero?
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqErr
4
+ class Error < StandardError; end
5
+ class NoProcessFound < Error; end
6
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqErr
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqErr
4
+ class View
5
+ class InvalidSection < SidekiqErr::Error; end
6
+
7
+ attr_reader :section
8
+
9
+ def self.valid_sections
10
+ @valid_sections ||= %w[all version overview processes queues].freeze
11
+ end
12
+
13
+ def initialize(section)
14
+ @section = section
15
+ end
16
+
17
+ def display
18
+ if invalid_section?(section)
19
+ msg = "Invalid section for status check: '#{section}'"
20
+ msg += "\nTry one of these: #{self.class.valid_sections.join(', ')}"
21
+ raise(InvalidSection, msg)
22
+ end
23
+
24
+ send(section)
25
+ end
26
+
27
+ def all
28
+ version
29
+ puts
30
+ overview
31
+ puts
32
+ processes
33
+ puts
34
+ queues
35
+ end
36
+
37
+ def version
38
+ puts "Sidekiq #{Sidekiq::VERSION}"
39
+ puts Time.now.utc
40
+ end
41
+
42
+ def overview
43
+ puts '---- Overview ----'
44
+ puts " Processed: #{delimit stats.processed}"
45
+ puts " Failed: #{delimit stats.failed}"
46
+ puts " Busy: #{delimit stats.workers_size}"
47
+ puts " Enqueued: #{delimit stats.enqueued}"
48
+ puts " Retries: #{delimit stats.retry_size}"
49
+ puts " Scheduled: #{delimit stats.scheduled_size}"
50
+ puts " Dead: #{delimit stats.dead_size}"
51
+ end
52
+
53
+ def processes
54
+ puts "---- Processes (#{process_set.size}) ----"
55
+ process_set.each_with_index do |process, index|
56
+ puts "#{process['identity']} #{tags_for(process)}"
57
+ puts " Started: #{Time.at(process['started_at'])} (#{time_ago(process['started_at'])})"
58
+ puts " Threads: #{process['concurrency']} (#{process['busy']} busy)"
59
+ puts " Queues: #{split_multiline(process['queues'].sort, pad: 11)}"
60
+ puts '' unless (index+1) == process_set.size
61
+ end
62
+ end
63
+
64
+ COL_PAD = 2
65
+ def queues
66
+ puts "---- Queues (#{queue_data.size}) ----"
67
+ columns = {
68
+ name: [:ljust, (['name'] + queue_data.map(&:name)).map(&:length).max + COL_PAD],
69
+ size: [:rjust, (['size'] + queue_data.map(&:size)).map(&:length).max + COL_PAD],
70
+ latency: [:rjust, (['latency'] + queue_data.map(&:latency)).map(&:length).max + COL_PAD]
71
+ }
72
+ columns.each { |col, (dir, width)| print col.to_s.upcase.public_send(dir, width) }
73
+ puts
74
+ queue_data.each do |q|
75
+ columns.each do |col, (dir, width)|
76
+ print q.send(col).public_send(dir, width)
77
+ end
78
+ puts
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def delimit(number)
85
+ number.to_s.reverse.scan(/.{1,3}/).join(',').reverse
86
+ end
87
+
88
+ def split_multiline(values, opts = {})
89
+ return 'none' unless values
90
+
91
+ pad = opts[:pad] || 0
92
+ max_length = opts[:max_length] || (80 - pad)
93
+ out = []
94
+ line = ''.dup
95
+ values.each do |value|
96
+ if (line.length + value.length) > max_length
97
+ out += line
98
+ line = ' ' * pad
99
+ end
100
+ line += "#{value}, "
101
+ end
102
+ out << line[0..-3]
103
+ out.join("\n")
104
+ end
105
+
106
+ def tags_for(process)
107
+ tags = [
108
+ process['tag'],
109
+ process['labels'],
110
+ (process['quiet'] == 'true' ? 'quiet' : nil)
111
+ ].flatten.compact
112
+ tags.any? ? "[#{tags.join('] [')}]" : nil
113
+ end
114
+
115
+ def time_ago(timestamp)
116
+ seconds = Time.now - Time.at(timestamp)
117
+ return 'just now' if seconds < 60
118
+ return 'a minute ago' if seconds < 120
119
+ return "#{seconds.floor / 60} minutes ago" if seconds < 3600
120
+ return 'an hour ago' if seconds < 7200
121
+
122
+ "#{seconds.floor / 60 / 60} hours ago"
123
+ end
124
+
125
+ QUEUE_STRUCT = Struct.new(:name, :size, :latency)
126
+ def queue_data
127
+ @queue_data ||= Sidekiq::Queue.all.map do |q|
128
+ QUEUE_STRUCT.new(q.name, q.size.to_s, sprintf('%#.2f', q.latency))
129
+ end
130
+ end
131
+
132
+ def process_set
133
+ @process_set ||= Sidekiq::ProcessSet.new
134
+ end
135
+
136
+ def stats
137
+ @stats ||= Sidekiq::Stats.new
138
+ end
139
+
140
+ def invalid_section?(section)
141
+ !self.class.valid_sections.include?(section)
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sidekiq-err/version'
4
+ require 'sidekiq-err/error'
5
+ require 'sidekiq-err/alive'
6
+ require 'sidekiq-err/view'
7
+ require 'fileutils'
8
+ require 'sidekiq/api'
9
+
10
+ module SidekiqErr
11
+ CMD = File.basename($PROGRAM_NAME)
12
+
13
+ def self.print_usage
14
+ puts "#{CMD} - Sidekiq process reporting."
15
+ puts
16
+ puts "Usage: #{CMD}"
17
+ puts
18
+ puts ' -a, --alive'
19
+ puts ' check if at least 1 Sidekiq process is running'
20
+ puts ' sets the exit code to 1 if no process if found'
21
+ puts
22
+ puts ' -r, --report [SECTION_NAME]'
23
+ puts ' view the status report'
24
+ puts ' SECTION_NAME is optional and filters the report to a specific section'
25
+ puts " Valid sections are: #{View.valid_sections.join(', ')}"
26
+ puts " Default is 'all'"
27
+ puts
28
+ end
29
+
30
+ def self.status(section = nil)
31
+ section ||= 'all'
32
+ SidekiqErr::View.new(section).display
33
+ end
34
+
35
+ def self.alive?
36
+ SidekiqErr::Alive.check?
37
+ end
38
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidekiq-err
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Campbell Allen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-12-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sidekiq
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Status of your sidekiq system - useful for Kubernetes liveness probes
70
+ email:
71
+ - campbell.allen@gmail.com
72
+ executables:
73
+ - sidekiq-err
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - exe/sidekiq-err
78
+ - lib/sidekiq-err.rb
79
+ - lib/sidekiq-err/alive.rb
80
+ - lib/sidekiq-err/error.rb
81
+ - lib/sidekiq-err/version.rb
82
+ - lib/sidekiq-err/view.rb
83
+ homepage: https://github.com/camallen/sidekiq-err
84
+ licenses:
85
+ - MIT
86
+ metadata:
87
+ homepage_uri: https://github.com/camallen/sidekiq-err
88
+ source_code_uri: https://github.com/camallen/sidekiq-err
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '2.4'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubygems_version: 3.0.1
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Status of your sidekiq system - useful for Kubernetes liveness probes
108
+ test_files: []