resque-job-killer 0.1.4 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f32a6868abf76e1682ebcfbfd8174032d01d96b8116898a8ba805ad3350ed48
4
- data.tar.gz: 248e5c7b92f58ab2a52b4c3c04a27cb5a126d4577e4980fe77509f4468c0b91a
3
+ metadata.gz: b76b0f851417e73b0fb83f2f5a7a8b4d2ee7642c5c17cafa365aef3f3fc5bbac
4
+ data.tar.gz: 73ebfe56a1999e692227ac17d3114ea94c2110465b1d3d7d09605263e115fe8b
5
5
  SHA512:
6
- metadata.gz: b5051390c2971a4030d536edfbeacb8eaee6ef1cc2191079f09924b8cbe5c8fa7e917e458f713abd869bf774ecd1c2fb7b517059cae78b0471c32007c4300c7b
7
- data.tar.gz: 0cba2b335e0ebd78d8640a78c4d500c662e668e504e8d8314ebb59912cb11d964b8532ffe763801df10f443d4d0b774384f6e7625b40bafe4742c3aa70691060
6
+ metadata.gz: 282af571a1208a0eff79254190c2d50cbb9d20ef23a181817f052b5b3ddca6227959bd99ecc845dc32da4d7eb62fc1d1143bebf8561e76e5faeae18906fb720f
7
+ data.tar.gz: b2862d071a2414f4d17045439179f19d1e6a44d9f7e0e1b7a449192345f448cce2a18cc85a8cb372cc5dc4742836f344f2cd600493bd1f07f803d3019b0a061a
@@ -1,46 +1,50 @@
1
1
  module Resque
2
2
  module Plugins
3
3
  module JobKiller
4
-
5
- MAX_HISTORY_SIZE = 500
6
- HISTORY_SET_NAME = "resque_history"
7
-
8
- def maximum_history_size
9
- @max_history ||= MAX_HISTORY_SIZE
4
+ def self.kill_job(job_id)
5
+ worker, queue = detect_worker_and_queue(job_id)
6
+ return unless worker
7
+
8
+ pause_worker(worker)
9
+ kill_child(worker)
10
+ dequeue_job(job_id, queue)
11
+ unpause_worker(worker)
10
12
  end
11
13
 
12
- def on_failure_history(exception, *args)
13
- Resque.redis.lpush(HISTORY_SET_NAME, {:class => "#{self}",
14
- :time => Time.now.strftime("%Y-%m-%d %H:%M:%S %z"),
15
- :args => args,
16
- :error => exception.message
17
- }.to_json)
14
+ private
18
15
 
19
- if Resque.redis.llen(HISTORY_SET_NAME) > maximum_history_size
20
- Resque.redis.rpop(HISTORY_SET_NAME)
21
- end
16
+ def detect_worker_and_queue(job_id)
17
+ worker = Resque.workers.detect do |worker|
18
+ worker.job.dig('payload', 'args')&.first&.dig('job_id') == job_id
19
+ end
22
20
 
21
+ [worker, worker.job['queue']]
23
22
  end
24
23
 
24
+ def kill_child(worker)
25
+ Process.kill(:USR1, worker.pid)
26
+ end
25
27
 
26
- def before_perform_history(*args)
27
- @start_time = Time.now
28
+ def pause_worker(worker)
29
+ Process.kill(:USR2, worker.pid)
28
30
  end
29
31
 
30
- def after_perform_history(*args)
31
- elapsed_seconds = (Time.now - @start_time).to_i
32
- Resque.redis.lpush(HISTORY_SET_NAME, {:class => "#{self}",
33
- :args => args,
34
- :time => Time.now.strftime("%Y-%m-%d %H:%M:%S %z"),
35
- :execution =>elapsed_seconds
36
- }.to_json)
32
+ def unpause_worker(worker)
33
+ Process.kill(:CONT, worker.pid)
34
+ end
37
35
 
38
- if Resque.redis.llen(HISTORY_SET_NAME) > maximum_history_size
39
- Resque.redis.rpop(HISTORY_SET_NAME)
40
- end
36
+ def dequeue_job(job_id, queue_name)
37
+ job = detect_job(job_id, queue_name)
41
38
 
39
+ Resque.redis.lrem("queue:#{queue_name}", -1, job)
42
40
  end
43
41
 
42
+ def detect_job(job_id, queue_name)
43
+ Resque.redis.lrange("queue:#{queue_name}", 0, -1)
44
+ .detect do |job|
45
+ Resque.decode(job).dig('args', 'job_id') == job_id
46
+ end
47
+ end
44
48
  end
45
49
  end
46
50
  end
@@ -1,62 +1,49 @@
1
- <% size = resque_history_total_jobs %>
2
- <% start = params[:start].to_i %>
3
- <% history = Resque.redis.lrange(resque_historyE, start, start + 20)%>
4
-
5
- <h1 class='wi'>Job history</h1>
6
-
7
- <% if size > 0 %>
8
- <form method="POST" action="<%=u 'history/clear'%>" class='clear-delayed'>
9
- <input type='submit' name='' value='Clear History' />
10
- </form>
11
- <% end %>
12
-
13
- <p class='intro'>Showing <%= start %> to
14
- <% if size > 20 %>
15
- <%= start + 20 %> of <b><%= size %></b>
16
- <% else %>
17
- <%= size %>
18
- <% end %>jobs</p>
19
-
20
- <div id="main">
21
- <%= erb File.read(ResqueHistory::Server.erb_path('navigation.erb')), {},
22
- :start => params[:start].to_i, :size => size %>
23
-
24
- <table>
1
+ <%
2
+ workers = resque.working
3
+ jobs = workers.collect {|w| w.job }
4
+ worker_jobs = workers.zip(jobs)
5
+ worker_jobs = worker_jobs.reject { |w, j| w.idle? }
6
+ %>
7
+
8
+ <h1 class='wi'><%= worker_jobs.size %> of <%= resque.workers.size %> Workers Working</h1>
9
+ <p class='intro'>The list below contains all workers which are currently running a job.</p>
10
+ <table class='workers'>
11
+ <tr>
12
+ <th>&nbsp;</th>
13
+ <th>Where</th>
14
+ <th>Queue</th>
15
+ <th>Processing</th>
16
+ <th> </th>
17
+ </tr>
18
+ <% if worker_jobs.empty? %>
25
19
  <tr>
26
- <th>Job</th>
27
- <th>Arguments</th>
28
- <th>Time</th>
29
- <th>Execution</th>
20
+ <td colspan="4" class='no-data'>Nothing is happening right now...</td>
30
21
  </tr>
31
- <% history.each do |history| %>
32
- <% j = JSON.parse(history, :symbolize_names => true, :symbolize_keys => true) %>
33
- <tr class='<%= j[:error].nil? ? "" : "failure" %>' >
34
- <td class='queue'><%= j[:class] %></td>
35
- <td class='argument'><pre><%= j[:args] ? show_args(j[:args]) : '' %></pre></td>
36
- <td class='time'><%= j[:time] %></td>
37
- <td class='execution'><%= format_execution(j[:execution]) %></td>
38
- </tr>
39
- <% end %>
40
- </table>
22
+ <% end %>
41
23
 
42
- <%= erb File.read(ResqueHistory::Server.erb_path('navigation.erb')), {},
43
- :start => params[:start].to_i, :size => size %>
44
- </div>
45
-
46
- <style type="text/css">
47
- #main table tr.failure td {
48
- background: #ffecec;
49
- border-top: 2px solid #d37474;
50
- font-size: 90%;
51
- color: #d37474;
52
- }
53
-
54
- .argument {
55
- max-width: 250px;
56
- word-wrap: break-word;
57
- }
58
-
59
- #main table tr.failure td a {
60
- color: #d37474;
61
- }
62
- </style>
24
+ <% worker_jobs.sort_by {|w, j| j['run_at'] ? j['run_at'].to_s() : '' }.each do |worker, job| %>
25
+ <tr>
26
+ <td class='icon'><img src="<%=u state = worker.state %>.png" alt="<%= state %>" title="<%= state %>"></td>
27
+ <% host, pid, queues = worker.to_s.split(':') %>
28
+ <td class='where'><a href="<%=u "/workers/#{worker}" %>"><%= host %>:<%= pid %></a></td>
29
+ <td class='queues queue'>
30
+ <a class="queue-tag" href="<%=u "/queues/#{job['queue']}" %>"><%= job['queue'] %></a>
31
+ </td>
32
+ <td class='process'>
33
+ <% if job['queue'] %>
34
+ <%= partial :processing, :worker => worker, :job => job %>
35
+ <% else %>
36
+ <span class='waiting'>Waiting for a job...</span>
37
+ <% end %>
38
+ </td>
39
+ <td>
40
+ <% job_id = job.dig('payload','args')&.first&.dig('job_id') %>
41
+ <% if job_id %>
42
+ <form method="DELETE" action="<%= u "job_killer/kill/#{job_id}" %>">
43
+ <input type="submit" name="" value="Kill job" onclick='return confirm("Are you absolutely sure? This cannot be undone.");' />
44
+ </form>
45
+ <% end %>
46
+ </td>
47
+ </tr>
48
+ <% end %>
49
+ </table>
@@ -23,10 +23,18 @@ module ResqueJobKiller
23
23
  erb File.read(ResqueJobKiller::Server.erb_path('job_killer.erb'))
24
24
  end
25
25
 
26
+ delete '/job_killer/kill:job_id' do
27
+ raise 'No job_id was provided' unless params[:job_id]
28
+
29
+ Resque::Plugins::JobKiller.kill_job(params[:job_id])
30
+
31
+ redirect 'resque/job_killer'
32
+ end
33
+
26
34
  end
27
35
  end
28
36
 
29
- Resque::Server.tabs << 'Job Killer'
37
+ Resque::Server.tabs << 'Job_Killer'
30
38
  end
31
39
  end
32
40
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque-job-killer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - fooooxmr