sidekiq-spy 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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