resque-sliders 0.0.4 → 0.0.5

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.
@@ -15,7 +15,7 @@ module Resque
15
15
 
16
16
  # Return Array of currently online hosts
17
17
  def hosts
18
- @host_status.keys.select { |x| x unless x.split(':').last == 'reload' }.map { |x| x.split(':').first }.uniq.sort
18
+ @host_status.keys.select { |x| x unless %w(reload pause stop).include? x.split(':').last }.map { |x| x.split(':').first }.uniq.sort
19
19
  end
20
20
 
21
21
  # Array of all hosts (current + stale)
@@ -62,11 +62,6 @@ module Resque
62
62
  redis_del_hash("#{key_prefix}:#{host}", queue)
63
63
  end
64
64
 
65
- # Sets reload flag on field of config_key to reload host's KEWatcher
66
- def reload(host)
67
- redis_set_hash(host_config_key, "#{host}:reload", 1)
68
- end
69
-
70
65
  end
71
66
  end
72
67
  end
@@ -36,15 +36,28 @@ module Resque
36
36
  redis_set_hash(host_config_key, "#{@hostname}:#{setting}", value)
37
37
  end
38
38
 
39
+ def unregister_setting(setting)
40
+ redis_del_hash(host_config_key, "#{@hostname}:#{setting}")
41
+ end
39
42
 
40
43
  # Signal Checking
41
44
 
42
-
43
45
  # Gets signal field in redis config_key for this host. Don't call directly
44
46
  def check_signal(host)
45
47
  sig = caller[0][/`([^']*)'/, 1].gsub('?', '')
46
48
  raise 'Dont call me that' unless %w(reload pause stop).include?(sig)
47
- redis_get_hash_field(host_config_key, "#{host}:#{sig}").to_i == 1 ? true : false
49
+ if @hostname
50
+ # if instance variable set from running daemon, make a freshy
51
+ redis_get_hash_field(host_config_key, "#{@hostname}:#{sig}").to_i == 1 ? true : false
52
+ else
53
+ # otherwise cache call in a Hash
54
+ @host_signal_map ||= {}
55
+ @host_signal_map[host] ||= {}
56
+ unless @host_signal_map[host].has_key?(sig)
57
+ @host_signal_map[host] = {sig => redis_get_hash_field(host_config_key, "#{host}:#{sig}").to_i == 1 ? true : false}.update(@host_signal_map[host])
58
+ end
59
+ @host_signal_map[host][sig]
60
+ end
48
61
  end
49
62
 
50
63
  def reload?(host)
@@ -59,12 +72,15 @@ module Resque
59
72
  check_signal(host)
60
73
  end
61
74
 
62
- # Return Hash of signals for host and their values
63
- #def check_redis_for_signals(host)
64
- # configs = redis_get_hash(host_config_key)
65
- # signals = %w(reload pause stop).map { |x| [host,x].join(':') }
66
- # Hash[configs.delete_if { |k,v| ! signals.include?(k) }.map { |k,v| [k.split(':').last.to_sym ,v] }]
67
- #end
75
+ # Set signal key given signal, host
76
+ def set_signal_flag(sig, host=@hostname)
77
+ @hostname ||= host
78
+ if sig == 'play'
79
+ %w(pause stop).each { |x| unregister_setting(x) }
80
+ else
81
+ register_setting(sig, 1)
82
+ end
83
+ end
68
84
 
69
85
  end
70
86
  end
@@ -51,26 +51,26 @@ module Resque
51
51
  count += 1
52
52
  log! ["watching:", @pids.keys.join(', '), "(#{@pids.keys.length})"].delete_if { |x| x == (nil || '') }.join(' ') if count % (10 / interval) == 1
53
53
 
54
+ tick = count % (20 / interval) == 1 ? true : false
55
+ (log! "checking signals..."; check_signals) if tick
54
56
  if not (paused? || shutdown?)
55
- if count % (20 / interval) == 1
56
- # do first and also about every 20 seconds so we can throttle calls to redis
57
- queue_diff!
58
- signal_hup if check_reload and not count == 1
59
- procline @pids.keys.join(', ')
60
- end
57
+ queue_diff! if tick # do first and also about every 20 seconds so we can throttle calls to redis
61
58
 
62
59
  while @pids.keys.length < @max_children && (@need_queues.length > 0 || @dead_queues.length > 0)
63
60
  queue = @dead_queues.shift || @need_queues.shift
64
61
  @pids.store(fork { exec("rake#{' -f ' + @rakefile if @rakefile}#{' environment' if ENV['RAILS_ENV']} resque:work QUEUE=#{queue}") }, queue) # store offset if linux fork() ?
65
- procline @pids.keys.join(', ')
62
+ procline
66
63
  end
67
64
  end
68
65
 
69
66
  register_setting('current_children', @pids.keys.length) if old != @pids.length
70
67
  old = @pids.length
71
68
 
69
+ procline if tick
70
+
72
71
  sleep(interval) # microsleep
73
72
  kill_zombies! # need to cleanup ones we've killed
73
+
74
74
  @pids.keys.each do |pid|
75
75
  begin
76
76
  # check to see if pid is running, by waiting for it, with a timeout
@@ -97,15 +97,6 @@ module Resque
97
97
 
98
98
  private
99
99
 
100
- def check_reload
101
- (unregister_setting('reload'); return true) if reload?(@hostname)
102
- false
103
- end
104
-
105
- def unregister_setting(setting)
106
- redis_del_hash(host_config_key, "#{@hostname}:#{setting}")
107
- end
108
-
109
100
  # Forces (via signal QUIT) any KEWatcher process running, located by ps and grep
110
101
  def restart_running!
111
102
  count = 0
@@ -126,6 +117,7 @@ module Resque
126
117
  log! "Found RAILS_ENV=#{ENV['RAILS_ENV']}" if ENV['RAILS_ENV']
127
118
  enable_gc_optimizations
128
119
  register_signal_handlers
120
+ clean_signal_settings
129
121
  register_setting('max_children', @max_children)
130
122
  log! "Registered Max Children with Redis"
131
123
  $stdout.sync = true
@@ -143,10 +135,10 @@ module Resque
143
135
 
144
136
  begin
145
137
  trap('QUIT') { shutdown! }
146
- trap('HUP') { signal_hup }
147
- trap('USR1') { signal_usr1 }
148
- trap('USR2') { signal_usr2 }
149
- trap('CONT') { signal_cont }
138
+ trap('HUP') { log "HUP received; purging children..."; signal_hup }
139
+ trap('USR1') { log "USR1 received; killing little children..."; set_signal_flag('stop'); signal_usr1 }
140
+ trap('USR2') { log "USR2 received; not making babies"; set_signal_flag('pause'); signal_usr2 }
141
+ trap('CONT') { log "CONT received; making babies..."; set_signal_flag('play'); signal_cont }
150
142
  rescue ArgumentError
151
143
  warn "Signals QUIT, USR1, USR2, and/or CONT not supported."
152
144
  end
@@ -154,8 +146,34 @@ module Resque
154
146
  log! "Registered signals"
155
147
  end
156
148
 
157
- def procline(string)
158
- $0 = "KEWatcher (#{@pids.keys.length}): #{string}"
149
+ def clean_signal_settings
150
+ %w(pause stop reload).each { |x| unregister_setting(x) }
151
+ end
152
+
153
+ # Check signals, do appropriate thing
154
+ def check_signals
155
+ if reload?(@hostname)
156
+ log ' -> RELOAD from web-ui'
157
+ signal_hup
158
+ @dead_queues = Array.new # clear killed queues because we're reloading in same tick as queue_diff!
159
+ elsif stop?(@hostname)
160
+ log ' -> STOPPED from web-ui' if not paused? or @pids.keys.length > 0
161
+ signal_usr1
162
+ elsif pause?(@hostname)
163
+ log ' -> PAUSED from web-ui' unless paused?
164
+ signal_usr2
165
+ else
166
+ log! ' -> Continuing; no signal found'
167
+ @dead_queues = Array.new if paused? # clear killed queues when entering out of pause automatically, in same tick will refresh
168
+ signal_cont
169
+ end
170
+ end
171
+
172
+ def procline(status=nil)
173
+ status ||= 'stopped' if paused? and @pids.keys.empty?
174
+ status ||= 'paused' if paused?
175
+ status = "#{[@pids.keys.length,status].compact.join('-')}" unless status == 'stopped'
176
+ $0 = "KEWatcher (#{status}): #{@pids.keys.join(', ')}"
159
177
  log! $0
160
178
  end
161
179
 
@@ -210,18 +228,18 @@ module Resque
210
228
  [to_start, to_kill] # return whats left
211
229
  end
212
230
 
231
+ # removes pid completely, ignores its queues
213
232
  def remove!(pid)
214
- # removes pid completely, ignores its queues
215
233
  kill_child pid
216
234
  @pids.delete(pid)
217
- procline @pids.keys.join(', ')
235
+ procline
218
236
  end
219
237
 
238
+ # remove pid, and respawn same queues
220
239
  def remove(pid)
221
- # remove pid, and respawn same queues
222
240
  @dead_queues.unshift(@pids[pid]) # keep track of queues that pid was running, put it at front of list
223
241
  @pids.delete(pid)
224
- procline @pids.keys.join(', ')
242
+ procline
225
243
  end
226
244
 
227
245
  def shutdown!
@@ -242,25 +260,26 @@ module Resque
242
260
  @paused
243
261
  end
244
262
 
263
+ # Reload
245
264
  def signal_hup
246
- log "HUP received; purging children..."
265
+ clean_signal_settings
247
266
  kill_children
248
267
  @paused = false # unpause after kill (restart child)
249
268
  end
250
269
 
270
+ # Stop
251
271
  def signal_usr1
252
- log "USR1 received; killing little children..."
253
272
  kill_children
254
273
  @paused = true # pause after kill cause we're paused
255
274
  end
256
275
 
276
+ # Pause
257
277
  def signal_usr2
258
- log "USR2 received; not making babies"
259
278
  @paused = true # paused again
260
279
  end
261
280
 
281
+ # Continue
262
282
  def signal_cont
263
- log "CONT received; making babies..."
264
283
  @paused = false # unpause
265
284
  end
266
285
 
@@ -1,8 +1,10 @@
1
1
  .icons {
2
2
  float: left;
3
+ margin: 0 2.5px 0 2.5px;
3
4
  }
4
5
  .corner {
5
6
  float: right;
7
+ margin: 2px 2.5px 0 2.5px;
6
8
  }
7
9
  #sliders {
8
10
  padding: 10px;
@@ -16,14 +16,40 @@ $(document).ready(function() {
16
16
  });
17
17
  return new_ary.join(',');
18
18
  };
19
- // Click function for all HUP icons
20
- $(".HUP").click(function() {
21
- var host = $(this).attr("id").replace('-HUP', '');
22
- $.post('/sliders/' + host, { reload: true }, function(data) {
23
- // FIXME
24
- // this should just show the alert icon
25
- window.location.reload();
26
- });
19
+ // Click function for all icons
20
+ $(".ui-icon").click(function() {
21
+ var host_sig = $(this).attr("id").split('-');
22
+ var host = host_sig[0];
23
+ switch(host_sig[1])
24
+ {
25
+ case 'REFRESH':
26
+ sig = 'reload';
27
+ break;
28
+ case 'ALERT':
29
+ return false;
30
+ default:
31
+ sig = host_sig[1].toLowerCase();
32
+ }
33
+ var signal = {};
34
+ signal[sig] = true;
35
+
36
+ var span = $(this);
37
+ $.post('/sliders/' + host, signal, function(data) {
38
+ switch(data.signal) {
39
+ case 'reload':
40
+ span.removeClass('ui-icon-refresh').addClass('ui-icon-alert').attr('id', [host, 'ALERT'].join('-'));
41
+ break;
42
+ case 'pause':
43
+ span.removeClass('ui-icon-pause').addClass('ui-icon-play').attr('id', [host, 'PLAY'].join('-'));
44
+ break;
45
+ case 'play':
46
+ span.removeClass('ui-icon-play').addClass('ui-icon-pause').attr('id', [host, 'PAUSE'].join('-'));
47
+ break;
48
+ case 'stop':
49
+ $('#'+ host + '-PAUSE').removeClass('ui-icon-pause').addClass('ui-icon-play').attr('id', [host, 'PLAY'].join('-'));
50
+ break;
51
+ }
52
+ }, "json");
27
53
  });
28
54
  $('.new_form').submit(function() {
29
55
  var queue = sanitize_input($("#new_queue").val());
@@ -12,10 +12,7 @@
12
12
  <% max = @sliders.max_children(host) || 'Not running' %>
13
13
 
14
14
  <h2><%= "#{host} (Total: <span id=\"total\"></span> Max: <span id=\"max\">#{max}</span>)" %>
15
- <span id="<%= host %>-HUP" class="ui-icon ui-icon-refresh ui-corner-all ui-state-default corner HUP"></span>
16
- <% if @sliders.reload?(host) %>
17
- <span class="ui-icon ui-icon-alert corner"></span>
18
- <% end %>
15
+ <%= daemon_buttons(host, false) %>
19
16
  </h2>
20
17
  <% @sliders.queue_values(host).each_pair do |queue,value| %>
21
18
  <p>
@@ -33,7 +30,7 @@
33
30
  <tr>
34
31
  <th>Hostname</th>
35
32
  <th>Current / Max Workers</th>
36
- <th>HUP</th>
33
+ <th>Controls</th>
37
34
  </tr>
38
35
  <% @sliders.all_hosts.each do |host| %>
39
36
  <tr>
@@ -46,10 +43,7 @@
46
43
  </td>
47
44
  <td>
48
45
  <ul>
49
- <li class="icons"><span id="<%= host %>-HUP" class="ui-icon ui-icon-refresh ui-corner-all ui-state-default HUP"></span></li>
50
- <% if @sliders.reload?(host) %>
51
- <li class="icons"><span class="ui-icon ui-icon-alert"></span></li>
52
- <% end %>
46
+ <%= daemon_buttons(host) %>
53
47
  </ul>
54
48
  </td>
55
49
  </tr>
@@ -28,6 +28,7 @@ module Resque
28
28
  end
29
29
 
30
30
  app.post '/sliders/:host' do
31
+ signals = params.reject { |x,y| x unless %w(pause stop play reload).include? x.to_s and y }
31
32
  if params[:quantity] && params[:queue]
32
33
  sliders = Commander.new
33
34
  queue = params[:queue].split.first
@@ -37,9 +38,12 @@ module Resque
37
38
  else
38
39
  sliders.change(params[:host], queue, quantity)
39
40
  end
40
- elsif params[:reload]
41
+ elsif signals.length == 1
41
42
  sliders = Commander.new
42
- sliders.reload(params[:host])
43
+ sig = signals.keys.first.to_s
44
+ sliders.set_signal_flag(sig, params[:host])
45
+ content_type :json
46
+ {:signal => sig, :host => params[:host]}.to_json
43
47
  end
44
48
  end
45
49
 
@@ -57,6 +61,29 @@ module Resque
57
61
  404
58
62
  end
59
63
  end
64
+
65
+ def daemon_buttons(host, list=true)
66
+ html_out = []
67
+ icon_base = 'ui-icon ui-corner-all ui-state-default'
68
+ case
69
+ when @sliders.reload?(host)
70
+ %w(pause stop alert)
71
+ when (@sliders.pause?(host) or @sliders.stop?(host))
72
+ %w(play stop refresh)
73
+ else
74
+ %w(pause stop refresh)
75
+ end.each do |i|
76
+ id = "#{host}-#{i.upcase}"
77
+ klass = "#{icon_base} ui-icon-#{i}"
78
+ klass += ' corner' unless list
79
+ html_out << "<span id=\"#{id}\" class=\"#{klass}\"></span>"
80
+ end
81
+ if list
82
+ '<li class="icons">' + html_out.join("</li><li class=\"icons\">") + '</li>'
83
+ else
84
+ html_out.reverse.join
85
+ end
86
+ end
60
87
  end
61
88
 
62
89
  app.tabs << "Sliders"
@@ -1,7 +1,7 @@
1
1
  module Resque
2
2
  module Plugins
3
3
  module ResqueSliders
4
- Version = VERSION = '0.0.4'
4
+ Version = VERSION = '0.0.5'
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque-sliders
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 4
10
- version: 0.0.4
9
+ - 5
10
+ version: 0.0.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kevin Mullin
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-05 00:00:00 -08:00
18
+ date: 2012-01-10 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency