sidekiq-spy 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 91574e1eabbcadaf02cc6fe5e70e3031e7022b33
4
- data.tar.gz: da4ab6eb49ee18c42665a627abc08df7529e4972
3
+ metadata.gz: b36dea1a5c807a96adeb6f29737175c479fa5e17
4
+ data.tar.gz: b6f96e42e80c5af6a31c7ee959c2b137c5ab68b4
5
5
  SHA512:
6
- metadata.gz: 49c09665f4349ada057861bb8d9f02dbd2a473ea33ad4fc0843613d03429228fc707b1dae3fb5a5c092d7a9725c5b9e6d4a55a17698a99cf98dc9573c7e2c36a
7
- data.tar.gz: 0b80737bf8f199ff2be3daa6e41746438ee55033d23926c106f9228fdad43a58476bcf4020c4eb41206a564a84197c9a6660e38a2639f2821b94a35aa0565736
6
+ metadata.gz: 675ab03fb9c9ca6069c8c92f6bac13c829be63b83f6e1fcb8c0ac36c4e34e20c28bf3b6f1a83039d79a1d2902a2fac34015cb34103843e862a5d8c419c20b138
7
+ data.tar.gz: ed53c6bd5d7a6ec01e18a91e056dee64fe3c8067dbef7d89614a439d84e2c0aa33a15f14253a1b0fb56fdcc8cf94231c5cf76aea97cfc6385636ca78bc53028e
data/CHANGELOG.md CHANGED
@@ -6,14 +6,16 @@ For many of commits by [tiredpixel](http://www.tiredpixel.com), the commit
6
6
  message provides information and examples.
7
7
 
8
8
 
9
- ## 0.1.0
9
+ ## 0.3.0
10
10
 
11
- - first release
12
- - `sidekiq-spy` executable providing: `--url`, `--host`, `--port`, `--database`,
13
- `--namespace`, `--interval`, `--help`, `--version`
14
- - core Redis statistics: redis, namespace, redis version, uptime (d),
15
- connections, memory, memory peak
16
- - core Sidekiq statistics: busy, retries, processed, enqueued, scheduled, failed
11
+ - sporadic screen-misdraws fix
12
+ - redraw on terminal window resize
13
+ - thread-waking instead of sleep increments for faster responses
14
+ - friendly error-reporting when unreachable host, etc.
15
+ - queues panel (like `Sidekiq::Web` Queues tab); press `<u>`
16
+ - retries panel (like `Sidekiq::Web` Retries tab); press `<r>`
17
+ - scheduled panel (like `Sidekiq::Web` Scheduled tab); press `<s>`
18
+ - `<w>` for existing (default) workers panel
17
19
 
18
20
 
19
21
  ## 0.2.0
@@ -25,3 +27,13 @@ message provides information and examples.
25
27
  - smaller sleep increments for faster exit
26
28
  - content overrun fix
27
29
  - workers panel (like `Sidekiq::Web` Workers tab), reporting who is up to what
30
+
31
+
32
+ ## 0.1.0
33
+
34
+ - first release
35
+ - `sidekiq-spy` executable providing: `--url`, `--host`, `--port`, `--database`,
36
+ `--namespace`, `--interval`, `--help`, `--version`
37
+ - core Redis statistics: redis, namespace, redis version, uptime (d),
38
+ connections, memory, memory peak
39
+ - core Sidekiq statistics: busy, retries, processed, enqueued, scheduled, failed
data/README.md CHANGED
@@ -13,12 +13,29 @@ no web server, this one's for you. <3
13
13
 
14
14
  This project is so hot out of the oven you might need mitts. But it's already
15
15
  functional, with the main statistics from the Sidekiq::Web homepage and the
16
- Workers tab. In time, it would be nice to add the Queues, Retries, and
17
- Scheduled tabs, too.
16
+ Workers, Queues, Retries, and Scheduled tabs.
18
17
 
19
18
  More sleep lost by [tiredpixel](http://www.tiredpixel.com).
20
19
 
21
20
 
21
+ ## ASCII Art (a.k.a. Screenshot)
22
+
23
+ Sidekiq Spy 0.3.0 WORKERS qUeues Retries Scheduled 16:17:23 +0000
24
+ redis: 127.0.0.1:6379/0|namespace:
25
+ redis version: 2.6.11|uptime (d): 2|connections: 5
26
+ memory: 4.89M|memory peak: 5.03M|
27
+
28
+ busy: 5|retries: 15|processed: 1623
29
+ enqueued: 0|scheduled: 0|failed: 1535
30
+
31
+ WORKER QUEUE CLASS ARGUMENTS STARTED
32
+ sep.da.local:17045-70130396 default MakeSEPFields [2670] 2013-11-03
33
+ sep.da.local:17045-70130397 default MakeSEPFields [2668] 2013-11-03
34
+ sep.da.local:17045-70130396 default MakeSEPFields [2669] 2013-11-03
35
+ sep.da.local:17045-70130397 default MakeSEPFields [2667] 2013-11-03
36
+ sep.da.local:17045-70130396 default MakeSEPFields [2671] 2013-11-03
37
+
38
+
22
39
  ## Installation
23
40
 
24
41
  Install using:
@@ -50,25 +67,9 @@ We won't tell anyone! ;) (Resque is awesome, too!)
50
67
 
51
68
  $ sidekiq-spy -n resque
52
69
 
53
- To quit, press `<q>` or `<ctrl>+<c>`. That's about it.
70
+ Navigate between tabs using the `<w>`, `<u>`, `<r>`, `<s>` keys.
54
71
 
55
-
56
- ## ASCII Art (a.k.a. Screenshot)
57
-
58
- Sidekiq Spy 0.2.0 16:17:23 +0000
59
- redis: 127.0.0.1:6379/0|namespace:
60
- redis version: 2.6.11|uptime (d): 2|connections: 5
61
- memory: 4.89M|memory peak: 5.03M|
62
-
63
- busy: 5|retries: 15|processed: 1623
64
- enqueued: 0|scheduled: 0|failed: 1535
65
-
66
- WORKER QUEUE CLASS ARGUMENTS STARTED
67
- sep.da.local:17045-70130396 default MakeSEPFields [2670] 2013-11-03
68
- sep.da.local:17045-70130397 default MakeSEPFields [2668] 2013-11-03
69
- sep.da.local:17045-70130396 default MakeSEPFields [2669] 2013-11-03
70
- sep.da.local:17045-70130397 default MakeSEPFields [2667] 2013-11-03
71
- sep.da.local:17045-70130396 default MakeSEPFields [2671] 2013-11-03
72
+ To quit, press `<q>` or `<ctrl>+<c>`. That's about it.
72
73
 
73
74
 
74
75
  ## Stay Tuned
@@ -84,9 +85,9 @@ That was easy.
84
85
 
85
86
  Dear Me, Here is a vague wishlist:
86
87
 
87
- - Queues page
88
- - Retries page
89
- - Scheduled page
88
+ - Queue (not Queues) page
89
+ - Retry (not Retries) page
90
+ - Paginated data
90
91
  - a little control to go with your monitoring, maybe...
91
92
 
92
93
 
data/bin/sidekiq-spy CHANGED
@@ -55,6 +55,10 @@ OptionParser.new do |opts|
55
55
 
56
56
  opts.separator ""
57
57
 
58
+ opts.on("--debug", "Run in debug mode") do |o|
59
+ options[:debug] = o
60
+ end
61
+
58
62
  opts.on_tail("--help",
59
63
  "Output (this) help and exit"
60
64
  ) do
@@ -95,5 +99,16 @@ end
95
99
  # = Run app
96
100
 
97
101
  trap('INT') { @app.stop }
102
+ trap('WINCH') { @app.restart }
98
103
 
99
- @app.start
104
+ begin
105
+ @app.start
106
+ rescue => e
107
+ warn "#{$0}: #{e}"
108
+
109
+ if options[:debug]
110
+ raise # reraise for stacktrace
111
+ else
112
+ exit 1 # same non-zero status as when --debug
113
+ end
114
+ end
data/lib/sidekiq-spy.rb CHANGED
@@ -6,6 +6,9 @@ require File.expand_path('../sidekiq-spy/app', __FILE__)
6
6
 
7
7
  require File.expand_path('../sidekiq-spy/spy/stats', __FILE__)
8
8
  require File.expand_path('../sidekiq-spy/spy/workers', __FILE__)
9
+ require File.expand_path('../sidekiq-spy/spy/queues', __FILE__)
10
+ require File.expand_path('../sidekiq-spy/spy/retries', __FILE__)
11
+ require File.expand_path('../sidekiq-spy/spy/schedules', __FILE__)
9
12
 
10
13
  require File.expand_path('../sidekiq-spy/display/screen', __FILE__)
11
14
  require File.expand_path('../sidekiq-spy/display/panel', __FILE__)
@@ -15,3 +18,6 @@ require File.expand_path('../sidekiq-spy/display/panels/header', __FILE__)
15
18
  require File.expand_path('../sidekiq-spy/display/panels/redis_stats', __FILE__)
16
19
  require File.expand_path('../sidekiq-spy/display/panels/sidekiq_stats', __FILE__)
17
20
  require File.expand_path('../sidekiq-spy/display/panels/workers', __FILE__)
21
+ require File.expand_path('../sidekiq-spy/display/panels/queues', __FILE__)
22
+ require File.expand_path('../sidekiq-spy/display/panels/retries', __FILE__)
23
+ require File.expand_path('../sidekiq-spy/display/panels/schedules', __FILE__)
@@ -1,17 +1,16 @@
1
- require 'thread'
2
1
  require 'sidekiq'
3
2
 
4
3
 
5
4
  module SidekiqSpy
6
5
  class App
7
6
 
8
- REFRESH_SUBINTERVAL = 0.1
9
-
10
7
  attr_reader :running
8
+ attr_reader :restarting
11
9
 
12
10
  def initialize
13
- @running = false
14
- @threads = {}
11
+ @running = false
12
+ @restarting = false
13
+ @threads = {}
15
14
  end
16
15
 
17
16
  def config
@@ -46,13 +45,29 @@ module SidekiqSpy
46
45
 
47
46
  def stop
48
47
  @running = false
48
+
49
+ wakey_wakey # for Ctrl+C route; #do_command route already wakes threads
50
+ end
51
+
52
+ def restart
53
+ @restarting = true
49
54
  end
50
55
 
51
56
  def do_command(key)
52
57
  case key
53
- when 'q' # quit
54
- @running = false
58
+ when 'q' # Q is very natural for Quit; Queues comes second to this
59
+ stop
60
+ when 'w'
61
+ @screen.panel_main = :workers
62
+ when 'u' # Q is already taken
63
+ @screen.panel_main = :queues
64
+ when 'r'
65
+ @screen.panel_main = :retries
66
+ when 's'
67
+ @screen.panel_main = :schedules
55
68
  end
69
+
70
+ wakey_wakey # wake threads for immediate response
56
71
  end
57
72
 
58
73
  private
@@ -67,9 +82,23 @@ module SidekiqSpy
67
82
  end
68
83
  end
69
84
 
85
+ def setup
86
+ @screen = Display::Screen.new
87
+ end
88
+
89
+ def cleanup
90
+ @screen.close if @screen
91
+ end
92
+
93
+ def wakey_wakey
94
+ @threads.each { |tname, t| t.run if t.status == 'sleep' }
95
+ end
96
+
70
97
  def command_loop
71
98
  while @running do
72
- key = next_key
99
+ next unless @screen # #refresh_loop might be reattaching screen
100
+
101
+ key = @screen.next_key
73
102
 
74
103
  next unless key # keep listening if timeout
75
104
 
@@ -79,33 +108,25 @@ module SidekiqSpy
79
108
 
80
109
  def refresh_loop
81
110
  while @running do
82
- refresh
83
-
84
- @sleep_timer = config.interval
111
+ next unless @screen # HACK: only certain test scenarios?
85
112
 
86
- while @running && @sleep_timer > 0
87
- sleep REFRESH_SUBINTERVAL
113
+ if @restarting || @screen.missized? # signal(s) or whilst still resizing
114
+ panel_main = @screen.panel_main
88
115
 
89
- @sleep_timer -= REFRESH_SUBINTERVAL
116
+ cleanup
117
+
118
+ setup
119
+
120
+ @screen.panel_main = panel_main
121
+
122
+ @restarting = false
90
123
  end
124
+
125
+ @screen.refresh
126
+
127
+ sleep config.interval # go to sleep; could be rudely awoken on quit
91
128
  end
92
129
  end
93
130
 
94
- def setup
95
- @screen = Display::Screen.new
96
- end
97
-
98
- def refresh
99
- @screen.refresh if @screen
100
- end
101
-
102
- def next_key
103
- @screen.next_key if @screen
104
- end
105
-
106
- def cleanup
107
- @screen.close if @screen
108
- end
109
-
110
131
  end
111
132
  end
@@ -3,18 +3,27 @@ module SidekiqSpy
3
3
  module Panels
4
4
  class Header < Display::Panel
5
5
 
6
+ attr_accessor :panel_main
7
+
6
8
  def initialize(height, width, top, left)
7
- super(height, width, top, left, structure)
9
+ super(height, width, top, left, structure, :divider_r => " ")
8
10
  end
9
11
 
10
12
  def structure
13
+ @panel_main = nil # set by Display::Screen#main_panel=
14
+
11
15
  # [
12
16
  # [relative_column_width, data_left, data_right]
13
17
  # ]
14
18
  [
15
19
  [
16
20
  [1, t[:program], nil],
17
- [1, nil, -> { Time.now.strftime("%T %z") }],
21
+ [2, -> {
22
+ [:workers, :queues, :retries, :schedules].map do |e|
23
+ t[:menu][(e == @panel_main ? :active : :inactive)][e]
24
+ end.join(" ")
25
+ }, nil],
26
+ [1, nil, -> { Time.now.strftime("%T %z") }],
18
27
  ],
19
28
  ]
20
29
  end
@@ -0,0 +1,44 @@
1
+ module SidekiqSpy
2
+ module Display
3
+ module Panels
4
+ class Queues < Display::Panel
5
+
6
+ def initialize(height, width, top, left)
7
+ @height = height # #structure needs this before #initialize ends
8
+
9
+ super(height, width, top, left, structure, :divider_r => " ")
10
+ end
11
+
12
+ def refresh
13
+ @queues.refresh # refresh data feed
14
+
15
+ super
16
+ end
17
+
18
+ def structure
19
+ @queues = Spy::Queues.new
20
+
21
+ # [
22
+ # [relative_column_width, data_left, data_right]
23
+ # ]
24
+ s = [
25
+ [ # table header slots
26
+ [2, t[:heading][:queue], nil],
27
+ [1, nil, t[:heading][:size]],
28
+ ],
29
+ ]
30
+
31
+ (0...(@height - 1)).each do |i|
32
+ s << [ # table row slots
33
+ [2, -> { @queues.data.values[i][:name] rescue nil }, nil],
34
+ [1, nil, -> { @queues.data.values[i][:size] rescue nil }],
35
+ ]
36
+ end
37
+
38
+ s
39
+ end
40
+
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,52 @@
1
+ module SidekiqSpy
2
+ module Display
3
+ module Panels
4
+ class Retries < Display::Panel
5
+
6
+ def initialize(height, width, top, left)
7
+ @height = height # #structure needs this before #initialize ends
8
+
9
+ super(height, width, top, left, structure, :divider_r => " ")
10
+ end
11
+
12
+ def refresh
13
+ @retries.refresh # refresh data feed
14
+
15
+ super
16
+ end
17
+
18
+ def structure
19
+ @retries = Spy::Retries.new
20
+
21
+ # [
22
+ # [relative_column_width, data_left, data_right]
23
+ # ]
24
+ s = [
25
+ [ # table header slots
26
+ [1, t[:heading][:next_at], nil],
27
+ [1, t[:heading][:count], nil],
28
+ [1, t[:heading][:queue], nil],
29
+ [1, t[:heading][:class], nil],
30
+ [1, t[:heading][:args], nil],
31
+ [1, nil, t[:heading][:error]],
32
+ ],
33
+ ]
34
+
35
+ (0...(@height - 1)).each do |i|
36
+ s << [ # table row slots
37
+ [1, -> { @retries.data[i][:next_at] rescue nil }, nil],
38
+ [1, -> { @retries.data[i][:count] rescue nil }, nil],
39
+ [1, -> { @retries.data[i][:queue] rescue nil }, nil],
40
+ [1, -> { @retries.data[i][:class] rescue nil }, nil],
41
+ [1, -> { @retries.data[i][:args] rescue nil }, nil],
42
+ [1, nil, -> { @retries.data[i][:error_class] rescue nil }],
43
+ ]
44
+ end
45
+
46
+ s
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,48 @@
1
+ module SidekiqSpy
2
+ module Display
3
+ module Panels
4
+ class Schedules < Display::Panel
5
+
6
+ def initialize(height, width, top, left)
7
+ @height = height # #structure needs this before #initialize ends
8
+
9
+ super(height, width, top, left, structure, :divider_r => " ")
10
+ end
11
+
12
+ def refresh
13
+ @schedules.refresh # refresh data feed
14
+
15
+ super
16
+ end
17
+
18
+ def structure
19
+ @schedules = Spy::Schedules.new
20
+
21
+ # [
22
+ # [relative_column_width, data_left, data_right]
23
+ # ]
24
+ s = [
25
+ [ # table header slots
26
+ [1, t[:heading][:scheduled_at], nil],
27
+ [1, t[:heading][:queue], nil],
28
+ [1, t[:heading][:class], nil],
29
+ [1, nil, t[:heading][:args]],
30
+ ],
31
+ ]
32
+
33
+ (0...(@height - 1)).each do |i|
34
+ s << [ # table row slots
35
+ [1, -> { @schedules.data[i][:scheduled_at] rescue nil }, nil],
36
+ [1, -> { @schedules.data[i][:queue] rescue nil }, nil],
37
+ [1, -> { @schedules.data[i][:class] rescue nil }, nil],
38
+ [1, nil, -> { @schedules.data[i][:args] rescue nil }],
39
+ ]
40
+ end
41
+
42
+ s
43
+ end
44
+
45
+ end
46
+ end
47
+ end
48
+ end
@@ -17,19 +17,26 @@ module SidekiqSpy
17
17
  Curses.curs_set(0)
18
18
  Curses.timeout = CURSES_GETCH_TIMEOUT
19
19
 
20
- @height = Curses.lines
21
- @width = Curses.cols
20
+ @height = term_height
21
+ @width = term_width
22
22
 
23
23
  @panels = { # attach panels, defining height, width, top, left
24
- :header => Display::Panels::Header.new( 1, @width, 0, 0),
25
- :redis_stats => Display::Panels::RedisStats.new( 3, @width, 1, 0),
26
- :sidekiq_stats => Display::Panels::SidekiqStats.new(2, @width, 5, 0),
27
- :workers => Display::Panels::Workers.new( (@height - 8), @width, 8, 0),
24
+ :header => Display::Panels::Header.new( 1, @width, 0, 0),
25
+ :redis_stats => Display::Panels::RedisStats.new( 3, @width, 1, 0),
26
+ :sidekiq_stats => Display::Panels::SidekiqStats.new(2, @width, 5, 0),
28
27
  }
28
+
29
+ self.panel_main = :workers
30
+
31
+ Curses.refresh
32
+ rescue
33
+ close
34
+
35
+ raise
29
36
  end
30
37
 
31
38
  def close
32
- @panels.each { |pname, panel| panel.close }
39
+ @panels.each { |pname, panel| panel.close } if @panels
33
40
 
34
41
  Curses.close_screen
35
42
  end
@@ -42,6 +49,41 @@ module SidekiqSpy
42
49
  Curses.getch
43
50
  end
44
51
 
52
+ def missized?
53
+ @height != term_height || @width != term_width
54
+ end
55
+
56
+ def panel_main
57
+ @panels[:header].panel_main
58
+ end
59
+
60
+ def panel_main=(pname)
61
+ @panels[:header].panel_main = pname
62
+
63
+ @panels[:main].close if @panels[:main]
64
+
65
+ @panels[:main] = case pname
66
+ when :workers
67
+ Display::Panels::Workers.new((@height - 8), @width, 8, 0)
68
+ when :queues
69
+ Display::Panels::Queues.new((@height - 8), @width, 8, 0)
70
+ when :retries
71
+ Display::Panels::Retries.new((@height - 8), @width, 8, 0)
72
+ when :schedules
73
+ Display::Panels::Schedules.new((@height - 8), @width, 8, 0)
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def term_height
80
+ (ENV['LINES'] || Curses.lines).to_i
81
+ end
82
+
83
+ def term_width
84
+ (ENV['COLUMNS'] || Curses.cols).to_i
85
+ end
86
+
45
87
  end
46
88
  end
47
89
  end
@@ -47,7 +47,7 @@ module SidekiqSpy
47
47
  l = data_l.is_a?(Proc) ? data_l.call : data_l
48
48
  r = data_r.is_a?(Proc) ? data_r.call : data_r
49
49
 
50
- ("#{l}%#{width - (l ? l.length : 0)}s" % r)[0...width]
50
+ ("#{l}%#{width - l.to_s.length}s" % r)[0...width]
51
51
  end
52
52
 
53
53
  end
@@ -0,0 +1,31 @@
1
+ require 'sidekiq'
2
+
3
+
4
+ module SidekiqSpy
5
+ module Spy
6
+ class Queues
7
+
8
+ attr_reader :data
9
+
10
+ def initialize
11
+ @stats = Sidekiq::Stats.new
12
+
13
+ refresh
14
+ end
15
+
16
+ def refresh
17
+ h = {}
18
+
19
+ @stats.queues.each do |queue, size|
20
+ h[queue] = {
21
+ :name => queue,
22
+ :size => size,
23
+ }
24
+ end
25
+
26
+ @data = h
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,37 @@
1
+ require 'time'
2
+ require 'sidekiq'
3
+
4
+
5
+ module SidekiqSpy
6
+ module Spy
7
+ class Retries
8
+
9
+ attr_reader :data
10
+
11
+ def initialize
12
+ @retries = Sidekiq::RetrySet.new
13
+
14
+ refresh
15
+ end
16
+
17
+ def refresh
18
+ h = []
19
+
20
+ @retries.each do |retry_item|
21
+ h << {
22
+ :next_at => retry_item.at,
23
+ :count => retry_item['retry_count'],
24
+ :queue => retry_item['queue'],
25
+ :class => retry_item['class'],
26
+ :args => retry_item['args'],
27
+ :error_class => retry_item['error_class'],
28
+ :error_message => retry_item['error_message'],
29
+ }
30
+ end
31
+
32
+ @data = h
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ require 'sidekiq'
2
+
3
+
4
+ module SidekiqSpy
5
+ module Spy
6
+ class Schedules
7
+
8
+ attr_reader :data
9
+
10
+ def initialize
11
+ @schedules = Sidekiq::ScheduledSet.new
12
+
13
+ refresh
14
+ end
15
+
16
+ def refresh
17
+ h = []
18
+
19
+ @schedules.each do |schedule|
20
+ h << {
21
+ :scheduled_at => schedule.at,
22
+ :queue => schedule['queue'],
23
+ :class => schedule['class'],
24
+ :args => schedule['args'],
25
+ }
26
+ end
27
+
28
+ @data = h
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -4,6 +4,20 @@ module SidekiqSpy
4
4
  def t
5
5
  {
6
6
  program: "Sidekiq Spy #{VERSION}",
7
+ menu: {
8
+ inactive: {
9
+ workers: "Workers",
10
+ queues: "qUeues",
11
+ retries: "Retries",
12
+ schedules: "Scheduled",
13
+ },
14
+ active: {
15
+ workers: "WORKERS",
16
+ queues: "QUEUES",
17
+ retries: "RETRIES",
18
+ schedules: "SCHEDULED",
19
+ },
20
+ },
7
21
  redis: {
8
22
  connection: "redis:",
9
23
  namespace: "namespace:",
@@ -27,6 +41,11 @@ module SidekiqSpy
27
41
  class: "CLASS",
28
42
  args: "ARGUMENTS",
29
43
  started_at: "STARTED",
44
+ size: "SIZE",
45
+ next_at: "NEXT",
46
+ count: "COUNT",
47
+ error: "ERROR",
48
+ scheduled_at: "SCHEDULED",
30
49
  }
31
50
  }
32
51
  end
@@ -1,5 +1,5 @@
1
1
  module SidekiqSpy
2
2
 
3
- VERSION = '0.2.0'
3
+ VERSION = '0.3.0'
4
4
 
5
5
  end
@@ -19,7 +19,14 @@ end
19
19
  describe SidekiqSpy::App do
20
20
 
21
21
  before do
22
- SidekiqSpy::Display::Screen.stubs(:new)
22
+ @screen = stub(
23
+ :close => nil,
24
+ :refresh => nil,
25
+ :next_key => nil,
26
+ :missized? => nil
27
+ )
28
+
29
+ SidekiqSpy::Display::Screen.stubs(:new).returns(@screen)
23
30
 
24
31
  @app = SidekiqSpy::App.new
25
32
  end
@@ -28,6 +35,10 @@ describe SidekiqSpy::App do
28
35
  @app.running.must_equal false
29
36
  end
30
37
 
38
+ it "sets status not-restarting" do
39
+ @app.restarting.must_equal false
40
+ end
41
+
31
42
  describe "#configure" do
32
43
  it "configures Sidekiq" do
33
44
  Sidekiq.expects(:configure_client)
@@ -160,14 +171,14 @@ describe SidekiqSpy::App do
160
171
  start_and_stop_app(@app)
161
172
  end
162
173
 
163
- it "calls #refresh hook" do
164
- @app.expects(:refresh)
174
+ it "calls #refresh on screen" do
175
+ @screen.expects(:refresh)
165
176
 
166
177
  start_and_stop_app(@app)
167
178
  end
168
179
 
169
- it "calls #next_key hook" do
170
- @app.expects(:next_key).at_least_once
180
+ it "calls #next_key on screen" do
181
+ @screen.expects(:next_key).at_least_once
171
182
 
172
183
  start_and_stop_app(@app)
173
184
  end
@@ -191,9 +202,22 @@ describe SidekiqSpy::App do
191
202
  end
192
203
  end
193
204
 
205
+ describe "#restart" do
206
+ before do
207
+ @app.instance_variable_set(:@restarting, false)
208
+ end
209
+
210
+ it "sets status restarting" do
211
+ @app.restart
212
+
213
+ @app.restarting.must_equal true
214
+ end
215
+ end
216
+
194
217
  describe "#do_command" do
195
218
  before do
196
219
  @app.instance_variable_set(:@running, true)
220
+ @app.instance_variable_set(:@screen, @screen)
197
221
  end
198
222
 
199
223
  it "<q> sets status not-running" do
@@ -201,6 +225,18 @@ describe SidekiqSpy::App do
201
225
 
202
226
  @app.running.must_equal false
203
227
  end
228
+
229
+ it "<w> switches to Workers panel" do
230
+ @screen.expects(:panel_main=).with(:workers)
231
+
232
+ @app.do_command('w')
233
+ end
234
+
235
+ it "<u> switches to Queues panel" do
236
+ @screen.expects(:panel_main=).with(:queues)
237
+
238
+ @app.do_command('u')
239
+ end
204
240
  end
205
241
 
206
242
  end
@@ -27,18 +27,23 @@ describe SidekiqSpy::Display::Screen do
27
27
  :noecho => nil,
28
28
  :curs_set => nil,
29
29
  :timeout= => nil,
30
+ :refresh => nil,
30
31
  :lines => 24,
31
32
  :cols => 80
32
33
  )
33
34
 
34
35
  @panel = stub(
35
- :close => nil
36
+ :close => nil,
37
+ :panel_main= => nil
36
38
  )
39
+ @panel_w = @panel.dup
40
+ @panel_q = @panel.dup
37
41
 
38
42
  SidekiqSpy::Display::Panels::Header.stubs(:new).returns(@panel)
39
43
  SidekiqSpy::Display::Panels::RedisStats.stubs(:new).returns(@panel)
40
44
  SidekiqSpy::Display::Panels::SidekiqStats.stubs(:new).returns(@panel)
41
- SidekiqSpy::Display::Panels::Workers.stubs(:new).returns(@panel)
45
+ SidekiqSpy::Display::Panels::Workers.stubs(:new).returns(@panel_w)
46
+ SidekiqSpy::Display::Panels::Queues.stubs(:new).returns(@panel_q)
42
47
 
43
48
  @screen = SidekiqSpy::Display::Screen.new
44
49
  end
@@ -95,4 +100,46 @@ describe SidekiqSpy::Display::Screen do
95
100
  end
96
101
  end
97
102
 
103
+ describe "#missized?" do
104
+ it "returns false when not missized" do
105
+ @screen.stubs(:term_height).returns(24)
106
+ @screen.stubs(:term_width).returns(80)
107
+
108
+ @screen.missized?.must_equal false
109
+ end
110
+
111
+ it "returns true when missized" do
112
+ @screen.stubs(:term_height).returns(21)
113
+ @screen.stubs(:term_width).returns(40)
114
+
115
+ @screen.missized?.must_equal true
116
+ end
117
+ end
118
+
119
+ describe "#panel_main=" do
120
+ before do
121
+ @panels = @screen.instance_variable_get(:@panels)
122
+ end
123
+
124
+ it "defaults panel_main to workers" do
125
+ @panels[:main].must_equal @panel_w
126
+ end
127
+
128
+ it "sets panel_main to workers" do
129
+ @panels[:main] = nil
130
+
131
+ @screen.panel_main = :workers
132
+
133
+ @screen.instance_variable_get(:@panels)[:main].must_equal @panel_w
134
+ end
135
+
136
+ it "sets panel_main to queues" do
137
+ @panels[:main] = nil
138
+
139
+ @screen.panel_main = :queues
140
+
141
+ @screen.instance_variable_get(:@panels)[:main].must_equal @panel_q
142
+ end
143
+ end
144
+
98
145
  end
@@ -156,7 +156,7 @@ describe SidekiqSpy::Display::Subpanel do
156
156
 
157
157
  @subpanel = SidekiqSpy::Display::Subpanel.new(@window, 24, 80, 0, 0, {
158
158
  :data_l => -> { "the answer:" },
159
- :data_r => -> { 2 * 3 * 7 }
159
+ :data_r => -> { "42" }
160
160
  })
161
161
  end
162
162
 
@@ -168,6 +168,19 @@ describe SidekiqSpy::Display::Subpanel do
168
168
  @subpanel.refresh
169
169
  end
170
170
 
171
+ it "sets data when non-string" do
172
+ @subpanel = SidekiqSpy::Display::Subpanel.new(@window, 24, 10, 0, 0, {
173
+ :data_l => -> { 2 * 3 * 7 },
174
+ :data_r => -> { 42 }
175
+ })
176
+
177
+ @window.stubs(:setpos)
178
+
179
+ @window.expects(:addstr).with("42 42")
180
+
181
+ @subpanel.refresh
182
+ end
183
+
171
184
  it "sets empty data when nil" do
172
185
  @subpanel = SidekiqSpy::Display::Subpanel.new(@window, 24, 10, 0, 0, {
173
186
  :data_l => -> { nil },
@@ -0,0 +1,63 @@
1
+ require 'time'
2
+
3
+
4
+ require File.expand_path('../../../helper', __FILE__)
5
+
6
+ require File.expand_path('../../../../lib/sidekiq-spy/spy/queues', __FILE__)
7
+
8
+
9
+ describe SidekiqSpy::Spy::Queues do
10
+
11
+ before do
12
+ @sidekiq_queues_data = {
13
+ 'queue1' => 42,
14
+ }
15
+
16
+ @spy_queues_data = {
17
+ 'queue1' => {
18
+ :name => 'queue1',
19
+ :size => 42,
20
+ }
21
+ }
22
+
23
+ @sidekiq_queues_data2 = {
24
+ 'queue2' => 1764,
25
+ }
26
+
27
+ @spy_queues_data2 = {
28
+ 'queue2' => {
29
+ :name => 'queue2',
30
+ :size => 1764,
31
+ }
32
+ }
33
+
34
+ Sidekiq::Stats.stubs(:new).returns(stub(
35
+ :queues => @sidekiq_queues_data
36
+ ))
37
+
38
+ @queues = SidekiqSpy::Spy::Queues.new
39
+ end
40
+
41
+ describe "#initialize" do
42
+ it "sets data list of queues" do
43
+ @queues.data.must_equal(@spy_queues_data)
44
+ end
45
+ end
46
+
47
+ describe "#refresh" do
48
+ it "doesn't refresh if not called" do
49
+ @sidekiq_queues_data.merge!(@sidekiq_queues_data2)
50
+
51
+ @queues.data.must_equal(@spy_queues_data)
52
+ end
53
+
54
+ it "refreshes if called" do
55
+ @sidekiq_queues_data.merge!(@sidekiq_queues_data2)
56
+
57
+ @queues.refresh
58
+
59
+ @queues.data.must_equal(@spy_queues_data.merge(@spy_queues_data2))
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,83 @@
1
+ require 'time'
2
+
3
+
4
+ require File.expand_path('../../../helper', __FILE__)
5
+
6
+ require File.expand_path('../../../../lib/sidekiq-spy/spy/retries', __FILE__)
7
+
8
+
9
+ describe SidekiqSpy::Spy::Retries do
10
+
11
+ before do
12
+ @sidekiq_retries_data = [
13
+ {
14
+ 'retry_count' => 180,
15
+ 'queue' => 'Q',
16
+ 'class' => 'Geometry',
17
+ 'args' => ['Euclid', 360],
18
+ 'error_class' => 'MmmmmmmmPie',
19
+ 'error_message' => 'Pie pie pie!',
20
+ },
21
+ ].each { |e| e.define_singleton_method(:at) { Time.at(11202710605) } }
22
+
23
+ @spy_retries_data = [
24
+ {
25
+ :next_at => Time.parse('2325-01-01 00:03:25 +0000'),
26
+ :count => 180,
27
+ :queue => 'Q',
28
+ :class => 'Geometry',
29
+ :args => ['Euclid', 360],
30
+ :error_class => 'MmmmmmmmPie',
31
+ :error_message => 'Pie pie pie!',
32
+ },
33
+ ]
34
+
35
+ @sidekiq_retries_data2 = [
36
+ {
37
+ 'retry_count' => 90,
38
+ 'queue' => 'Queueueue',
39
+ 'class' => 'Elements',
40
+ 'args' => ['Lehrer', 102],
41
+ },
42
+ ].each { |e| e.define_singleton_method(:at) { Time.at(-1316908800) } }
43
+
44
+ @spy_retries_data2 = [
45
+ {
46
+ :next_at => Time.parse('1928-04-09 00:00:00 +0000'),
47
+ :count => 90,
48
+ :queue => 'Queueueue',
49
+ :class => 'Elements',
50
+ :args => ['Lehrer', 102],
51
+ :error_class => nil,
52
+ :error_message => nil,
53
+ },
54
+ ]
55
+
56
+ Sidekiq::RetrySet.stubs(:new).returns(@sidekiq_retries_data)
57
+
58
+ @retries = SidekiqSpy::Spy::Retries.new
59
+ end
60
+
61
+ describe "#initialize" do
62
+ it "sets data list of retries" do
63
+ @retries.data.must_equal(@spy_retries_data)
64
+ end
65
+ end
66
+
67
+ describe "#refresh" do
68
+ it "doesn't refresh if not called" do
69
+ @sidekiq_retries_data.push(*@sidekiq_retries_data2)
70
+
71
+ @retries.data.must_equal(@spy_retries_data)
72
+ end
73
+
74
+ it "refreshes if called" do
75
+ @sidekiq_retries_data.push(*@sidekiq_retries_data2)
76
+
77
+ @retries.refresh
78
+
79
+ @retries.data.must_equal(@spy_retries_data + @spy_retries_data2)
80
+ end
81
+ end
82
+
83
+ end
@@ -0,0 +1,73 @@
1
+ require 'time'
2
+
3
+
4
+ require File.expand_path('../../../helper', __FILE__)
5
+
6
+ require File.expand_path('../../../../lib/sidekiq-spy/spy/schedules', __FILE__)
7
+
8
+
9
+ describe SidekiqSpy::Spy::Schedules do
10
+
11
+ before do
12
+ @sidekiq_schedules_data = [
13
+ {
14
+ 'queue' => 'Q',
15
+ 'class' => 'Geometry',
16
+ 'args' => ['Euclid', 360],
17
+ },
18
+ ].each { |e| e.define_singleton_method(:at) { Time.at(11202710605) } }
19
+
20
+ @spy_schedules_data = [
21
+ {
22
+ :scheduled_at => Time.parse('2325-01-01 00:03:25 +0000'),
23
+ :queue => 'Q',
24
+ :class => 'Geometry',
25
+ :args => ['Euclid', 360],
26
+ },
27
+ ]
28
+
29
+ @sidekiq_schedules_data2 = [
30
+ {
31
+ 'queue' => 'Queueueue',
32
+ 'class' => 'Elements',
33
+ 'args' => ['Lehrer', 102],
34
+ },
35
+ ].each { |e| e.define_singleton_method(:at) { Time.at(-1316908800) } }
36
+
37
+ @spy_schedules_data2 = [
38
+ {
39
+ :scheduled_at => Time.parse('1928-04-09 00:00:00 +0000'),
40
+ :queue => 'Queueueue',
41
+ :class => 'Elements',
42
+ :args => ['Lehrer', 102],
43
+ },
44
+ ]
45
+
46
+ Sidekiq::ScheduledSet.stubs(:new).returns(@sidekiq_schedules_data)
47
+
48
+ @schedules = SidekiqSpy::Spy::Schedules.new
49
+ end
50
+
51
+ describe "#initialize" do
52
+ it "sets data list of schedules" do
53
+ @schedules.data.must_equal(@spy_schedules_data)
54
+ end
55
+ end
56
+
57
+ describe "#refresh" do
58
+ it "doesn't refresh if not called" do
59
+ @sidekiq_schedules_data.push(*@sidekiq_schedules_data2)
60
+
61
+ @schedules.data.must_equal(@spy_schedules_data)
62
+ end
63
+
64
+ it "refreshes if called" do
65
+ @sidekiq_schedules_data.push(*@sidekiq_schedules_data2)
66
+
67
+ @schedules.refresh
68
+
69
+ @schedules.data.must_equal(@spy_schedules_data + @spy_schedules_data2)
70
+ end
71
+ end
72
+
73
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-spy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tiredpixel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-03 00:00:00.000000000 Z
11
+ date: 2013-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq
@@ -90,11 +90,17 @@ files:
90
90
  - lib/sidekiq-spy/config.rb
91
91
  - lib/sidekiq-spy/display/panel.rb
92
92
  - lib/sidekiq-spy/display/panels/header.rb
93
+ - lib/sidekiq-spy/display/panels/queues.rb
93
94
  - lib/sidekiq-spy/display/panels/redis_stats.rb
95
+ - lib/sidekiq-spy/display/panels/retries.rb
96
+ - lib/sidekiq-spy/display/panels/schedules.rb
94
97
  - lib/sidekiq-spy/display/panels/sidekiq_stats.rb
95
98
  - lib/sidekiq-spy/display/panels/workers.rb
96
99
  - lib/sidekiq-spy/display/screen.rb
97
100
  - lib/sidekiq-spy/display/subpanel.rb
101
+ - lib/sidekiq-spy/spy/queues.rb
102
+ - lib/sidekiq-spy/spy/retries.rb
103
+ - lib/sidekiq-spy/spy/schedules.rb
98
104
  - lib/sidekiq-spy/spy/stats.rb
99
105
  - lib/sidekiq-spy/spy/workers.rb
100
106
  - lib/sidekiq-spy/translatable.rb
@@ -107,6 +113,9 @@ files:
107
113
  - test/sidekiq-spy/display/panel_test.rb
108
114
  - test/sidekiq-spy/display/screen_test.rb
109
115
  - test/sidekiq-spy/display/subpanel_test.rb
116
+ - test/sidekiq-spy/spy/queues_test.rb
117
+ - test/sidekiq-spy/spy/retries_test.rb
118
+ - test/sidekiq-spy/spy/schedules_test.rb
110
119
  - test/sidekiq-spy/spy/stats_test.rb
111
120
  - test/sidekiq-spy/spy/workers_test.rb
112
121
  - test/sidekiq-spy/translatable_test.rb
@@ -131,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
140
  version: '0'
132
141
  requirements: []
133
142
  rubyforge_project:
134
- rubygems_version: 2.1.10
143
+ rubygems_version: 2.1.11
135
144
  signing_key:
136
145
  specification_version: 4
137
146
  summary: Sidekiq monitoring in the console.
@@ -143,6 +152,9 @@ test_files:
143
152
  - test/sidekiq-spy/display/panel_test.rb
144
153
  - test/sidekiq-spy/display/screen_test.rb
145
154
  - test/sidekiq-spy/display/subpanel_test.rb
155
+ - test/sidekiq-spy/spy/queues_test.rb
156
+ - test/sidekiq-spy/spy/retries_test.rb
157
+ - test/sidekiq-spy/spy/schedules_test.rb
146
158
  - test/sidekiq-spy/spy/stats_test.rb
147
159
  - test/sidekiq-spy/spy/workers_test.rb
148
160
  - test/sidekiq-spy/translatable_test.rb