resque_manager 3.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.
Files changed (120) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README.markdown +417 -0
  4. data/Rakefile +41 -0
  5. data/app/assets/images/resque_manager/idle.png +0 -0
  6. data/app/assets/images/resque_manager/poll.png +0 -0
  7. data/app/assets/images/resque_manager/working.png +0 -0
  8. data/app/assets/javascripts/resque_manager/application.js +15 -0
  9. data/app/assets/javascripts/resque_manager/jquery-1.3.2.min.js +19 -0
  10. data/app/assets/javascripts/resque_manager/jquery.relatize_date.js +95 -0
  11. data/app/assets/javascripts/resque_manager/ranger.js +24 -0
  12. data/app/assets/stylesheets/resque_manager/application.css +14 -0
  13. data/app/assets/stylesheets/resque_manager/resque/resque.css +93 -0
  14. data/app/assets/stylesheets/resque_manager/resque/resque_reset.css +48 -0
  15. data/app/assets/stylesheets/resque_manager/resque_cleaner/cleaner.css +62 -0
  16. data/app/controllers/resque_manager/resque_controller.rb +313 -0
  17. data/app/helpers/resque_manager/application_helper.rb +4 -0
  18. data/app/helpers/resque_manager/resque_helper.rb +142 -0
  19. data/app/models/resque_manager/paginate.rb +54 -0
  20. data/app/views/layouts/resque_manager/application.html.erb +37 -0
  21. data/app/views/resque_manager/resque/_key.html.erb +17 -0
  22. data/app/views/resque_manager/resque/_limiter.html.erb +12 -0
  23. data/app/views/resque_manager/resque/_next_more.html.erb +10 -0
  24. data/app/views/resque_manager/resque/_paginate.html.erb +53 -0
  25. data/app/views/resque_manager/resque/_queues.html.erb +59 -0
  26. data/app/views/resque_manager/resque/_status_styles.erb +98 -0
  27. data/app/views/resque_manager/resque/_workers.html.erb +138 -0
  28. data/app/views/resque_manager/resque/_working.html.erb +69 -0
  29. data/app/views/resque_manager/resque/cleaner.html.erb +41 -0
  30. data/app/views/resque_manager/resque/cleaner_exec.html.erb +6 -0
  31. data/app/views/resque_manager/resque/cleaner_list.html.erb +172 -0
  32. data/app/views/resque_manager/resque/delayed.html.erb +35 -0
  33. data/app/views/resque_manager/resque/delayed_timestamp.html.erb +26 -0
  34. data/app/views/resque_manager/resque/error.erb +1 -0
  35. data/app/views/resque_manager/resque/overview.html.erb +4 -0
  36. data/app/views/resque_manager/resque/schedule.html.erb +96 -0
  37. data/app/views/resque_manager/resque/stats.html.erb +62 -0
  38. data/app/views/resque_manager/resque/status.html.erb +57 -0
  39. data/app/views/resque_manager/resque/statuses.html.erb +72 -0
  40. data/app/views/resque_manager/resque/workers.html.erb +1 -0
  41. data/config/routes.rb +38 -0
  42. data/config/sample_redis.yml +43 -0
  43. data/config/sample_resque_manager.yml +23 -0
  44. data/lib/resque_manager/engine.rb +9 -0
  45. data/lib/resque_manager/overrides/resque/failure/redis.rb +11 -0
  46. data/lib/resque_manager/overrides/resque/job.rb +69 -0
  47. data/lib/resque_manager/overrides/resque/resque.rb +8 -0
  48. data/lib/resque_manager/overrides/resque/worker.rb +291 -0
  49. data/lib/resque_manager/overrides/resque_scheduler/resque_scheduler.rb +58 -0
  50. data/lib/resque_manager/overrides/resque_status/chained_status.rb +46 -0
  51. data/lib/resque_manager/overrides/resque_status/hash.rb +12 -0
  52. data/lib/resque_manager/overrides/resque_status/status.rb +161 -0
  53. data/lib/resque_manager/recipes.rb +185 -0
  54. data/lib/resque_manager/version.rb +3 -0
  55. data/lib/resque_manager.rb +47 -0
  56. data/lib/tasks/failure.rake +8 -0
  57. data/lib/tasks/scheduler.rake +11 -0
  58. data/lib/tasks/worker.rake +129 -0
  59. data/test/dummy/README.rdoc +261 -0
  60. data/test/dummy/Rakefile +7 -0
  61. data/test/dummy/app/assets/javascripts/application.js +15 -0
  62. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  63. data/test/dummy/app/controllers/application_controller.rb +3 -0
  64. data/test/dummy/app/helpers/application_helper.rb +2 -0
  65. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  66. data/test/dummy/config/application.rb +65 -0
  67. data/test/dummy/config/boot.rb +10 -0
  68. data/test/dummy/config/environment.rb +5 -0
  69. data/test/dummy/config/environments/development.rb +37 -0
  70. data/test/dummy/config/environments/production.rb +67 -0
  71. data/test/dummy/config/environments/test.rb +37 -0
  72. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  73. data/test/dummy/config/initializers/inflections.rb +15 -0
  74. data/test/dummy/config/initializers/mime_types.rb +5 -0
  75. data/test/dummy/config/initializers/secret_token.rb +7 -0
  76. data/test/dummy/config/initializers/session_store.rb +8 -0
  77. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  78. data/test/dummy/config/locales/en.yml +5 -0
  79. data/test/dummy/config/routes.rb +4 -0
  80. data/test/dummy/config.ru +4 -0
  81. data/test/dummy/log/development.log +5045 -0
  82. data/test/dummy/public/404.html +26 -0
  83. data/test/dummy/public/422.html +26 -0
  84. data/test/dummy/public/500.html +25 -0
  85. data/test/dummy/public/favicon.ico +0 -0
  86. data/test/dummy/script/rails +6 -0
  87. data/test/dummy/tmp/cache/assets/C2A/A10/sprockets%2Fb2e622954654f415590723e9b882063e +0 -0
  88. data/test/dummy/tmp/cache/assets/C60/1D0/sprockets%2F8ed12e4193473760f95b973567a8c206 +0 -0
  89. data/test/dummy/tmp/cache/assets/CA1/970/sprockets%2Fc387148880e015d1eab0dc838b326022 +0 -0
  90. data/test/dummy/tmp/cache/assets/CAE/930/sprockets%2Fe227278d3c65d8aa1159da720263f771 +0 -0
  91. data/test/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  92. data/test/dummy/tmp/cache/assets/CDC/E30/sprockets%2Fe1207380d69eeee3284e02636c26f24a +0 -0
  93. data/test/dummy/tmp/cache/assets/CF1/720/sprockets%2Fd91a5918f5aa43a43c8135a67c78e989 +0 -0
  94. data/test/dummy/tmp/cache/assets/D0E/820/sprockets%2F00c6cc9dc46bf64347b3775d7d15541b +0 -0
  95. data/test/dummy/tmp/cache/assets/D16/180/sprockets%2F73d6fa09352cb76ac81e1683e832b93f +0 -0
  96. data/test/dummy/tmp/cache/assets/D27/170/sprockets%2Fec164819553e2e5b28f1efc9bd970978 +0 -0
  97. data/test/dummy/tmp/cache/assets/D2B/DA0/sprockets%2F989465d3ea8575dd0b54981a9e8add38 +0 -0
  98. data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  99. data/test/dummy/tmp/cache/assets/D37/1F0/sprockets%2F97119b908ebed2633edfd00ac90d9011 +0 -0
  100. data/test/dummy/tmp/cache/assets/D38/FB0/sprockets%2F74e5ba1cca7a1470d53c54fb60368b78 +0 -0
  101. data/test/dummy/tmp/cache/assets/D42/4E0/sprockets%2F0fa6e3c14356aa527d68a8d56fa37f28 +0 -0
  102. data/test/dummy/tmp/cache/assets/D43/C20/sprockets%2F1efd074fd1074b3dc88145b480ff961f +0 -0
  103. data/test/dummy/tmp/cache/assets/D46/CD0/sprockets%2F67f1ef70e7ede542318b8d55e25b16c3 +0 -0
  104. data/test/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  105. data/test/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  106. data/test/dummy/tmp/cache/assets/D68/080/sprockets%2Fa26f2ae225aa4b87c462d540c7cf43f9 +0 -0
  107. data/test/dummy/tmp/cache/assets/D9A/B20/sprockets%2F0eddc19d46318e2e286cc171ae4cc73e +0 -0
  108. data/test/dummy/tmp/cache/assets/DA4/900/sprockets%2F515bf984438c6ec4b8a515fcc13baf8e +0 -0
  109. data/test/dummy/tmp/cache/assets/DBD/070/sprockets%2F60ffef45ddefd5c7746d17977fff0717 +0 -0
  110. data/test/dummy/tmp/cache/assets/DD7/AC0/sprockets%2Fc7c983c5c607dbfdb726eecc36146ca9 +0 -0
  111. data/test/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  112. data/test/dummy/tmp/cache/assets/DF5/480/sprockets%2Fea4f3c726fc1046cad1ad243faf84e7d +0 -0
  113. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  114. data/test/dummy/tmp/cache/assets/E2B/7A0/sprockets%2Fd44ef07be0aa6d5b5dea4d37d7f72b4f +0 -0
  115. data/test/functional/resque_manager/resque_controller_test.rb +9 -0
  116. data/test/integration/navigation_test.rb +10 -0
  117. data/test/resque_manager_test.rb +7 -0
  118. data/test/test_helper.rb +15 -0
  119. data/test/unit/helpers/resque_manager/resque_helper_test.rb +6 -0
  120. metadata +307 -0
@@ -0,0 +1,59 @@
1
+ <% @partial ||= partial -%>
2
+
3
+ <% @subtabs = resque.queues unless partial? %>
4
+
5
+ <% if queue = params[:id] %>
6
+
7
+ <h1>Pending jobs on <span class='hl'><%= queue %></span></h1>
8
+ <p class='sub'>Showing <%= start = params[:start].to_i %> to <%= start + 20 %> of
9
+ <b><%= size = resque.size(queue) %></b> jobs</p>
10
+ <table class='jobs'>
11
+ <tr>
12
+ <th>Class</th>
13
+ <th>Args</th>
14
+ <% if ResqueManager.applications.blank? %>
15
+ <th>&nbsp;</th>
16
+ <% end %>
17
+ </tr>
18
+ <% for job in (jobs = resque.peek(queue, start, 20)) %>
19
+ <tr>
20
+ <td class='class'><%= job['class'] %></td>
21
+ <td class='args'><%= job['args'].inspect.html_safe %></td>
22
+ <% if ResqueManager.applications.blank? %>
23
+ <td>
24
+ <%= button_to "Remove", {:controller => 'resque', :action => 'remove_job', :class => job['class'], :args => Resque.encode(job['args'])}, :class => 'clear-failed', :method => :post %>
25
+ </td>
26
+ <% end %>
27
+ </tr>
28
+ <% end %>
29
+ <% if jobs.empty? %>
30
+ <tr>
31
+ <td class='no-data' colspan='3'>There are no pending jobs in this queue</td>
32
+ </tr>
33
+ <% end %>
34
+ </table>
35
+ <%= render(:partial => 'next_more', :locals => {:start => start, :size => size}) %>
36
+ <% else %>
37
+
38
+ <h1 class='wi'>Queues</h1>
39
+
40
+ <p class='intro'>The list below contains all the registered queues with the number of jobs currently in the
41
+ queue. Select a queue from above to view all jobs currently pending on the queue.</p>
42
+ <table class='queues'>
43
+ <tr>
44
+ <th>Name</th>
45
+ <th>Jobs</th>
46
+ </tr>
47
+ <% for queue in resque.queues.sort_by { |q| q.to_s } %>
48
+ <tr>
49
+ <td class='queue'><%= link_to(queue, {:action => "queues", :id => queue}, :class => 'queue') %></td>
50
+ <td class='size'><%= resque.size queue %></td>
51
+ </tr>
52
+ <% end %>
53
+ <tr class='failed'>
54
+ <td class='queue failed'><%= link_to('failed', {:action => "cleaner"}, :class => 'queue') %></td>
55
+ <td class='size'><%= Resque::Failure.count %></td>
56
+ </tr>
57
+ </table>
58
+
59
+ <% end %>
@@ -0,0 +1,98 @@
1
+ <style type="text/css" media="screen">
2
+ th.progress {
3
+ width: 100px;
4
+ }
5
+ td.progress {
6
+ position: relative;
7
+ width: 100px;
8
+ display:block;
9
+ }
10
+ td.status {
11
+ font-weight: bold;
12
+ }
13
+ td.progress .progress-bar {
14
+ position: absolute;
15
+ top: 0px;
16
+ left: 0px;
17
+ background: #999;
18
+ display:block;
19
+ height: 100%;
20
+ z-index: 0;
21
+ opacity: 0.5;
22
+ -moz-opacity: 0.5;
23
+ -webkit-opacity: 0.5;
24
+ }
25
+ td.progress .progress-pct {
26
+ z-index: 10;
27
+ color: #333;
28
+ }
29
+
30
+ .status-holder {
31
+ background: #F7F7F7;
32
+ border: 1px solid #E5E5E5;
33
+ padding: 20px;
34
+ font-size: 110%;
35
+ margin-bottom: 40px;
36
+ }
37
+ .status-progress {
38
+ width: 100%;
39
+ height: 30px;
40
+ border: 1px solid #CCC;
41
+ background: #E5E5E5;
42
+ position:relative;
43
+ margin: 5px 0px;
44
+ }
45
+ .status-progress-bar {
46
+ position:absolute;
47
+ top: 0px;
48
+ left: 0px;
49
+ height: 30px;
50
+ background: #CCC;
51
+ }
52
+ .status-progress p {
53
+ position:absolute;
54
+ top: 5px;
55
+ left: 10px;
56
+ z-index: 15;
57
+ display:block;
58
+ color: #FFF;
59
+ padding: 0px;
60
+ font-weight: bold;
61
+ }
62
+ .status-message {
63
+ font-weight: bold;
64
+ }
65
+ .status-time {
66
+ font-size: 70%;
67
+ padding: 10px 0px;
68
+ color: #999;
69
+ }
70
+ .status-progress-bar.status-completed {
71
+ background:#61BF55;
72
+ }
73
+ .status-progress-bar.status-failed {
74
+ background: #E47E74;
75
+ }
76
+ .status-progress-bar.status-working {
77
+ background: #528499;
78
+ }
79
+ .status-progress-bar.status-killed {
80
+ background: #B84F16;
81
+ }
82
+ .status-completed {
83
+ color:#61BF55;
84
+ }
85
+ .status-failed {
86
+ color: #E47E74;
87
+ }
88
+ .status-working {
89
+ color: #528499;
90
+ }
91
+ .status-killed {
92
+ color: #B84F16;
93
+ }
94
+ #main a.kill:link, #main a.kill:visited {
95
+ color: #B84F16;
96
+ font-weight: bold;
97
+ }
98
+ </style>
@@ -0,0 +1,138 @@
1
+ <% if params[:id] && worker = find_worker(params[:id]) %>
2
+
3
+ <h1>Worker <%= worker %></h1>
4
+ <table class='workers'>
5
+ <tr>
6
+ <th>&nbsp;</th>
7
+ <th>Host</th>
8
+ <th>Path</th>
9
+ <th>Pid</th>
10
+ <th>Thread</th>
11
+ <th>Started</th>
12
+ <th>Paused</th>
13
+ <th>Queues</th>
14
+ <th>Processed</th>
15
+ <th>Failed</th>
16
+ <th>Processing</th>
17
+ </tr>
18
+ <tr>
19
+ <td class='icon'>
20
+ <img src="<%= "/assets/resque_manager/#{state = worker.state}" %>.png" alt="<%= state %>" title="<%= state %>">
21
+ </td>
22
+
23
+ <% host, pid, thread, path, queues = worker.to_s.split(':') %>
24
+ <td><%= host %></td>
25
+ <td><%= path %></td>
26
+ <td><%= pid %></td>
27
+ <td><%= thread %></td>
28
+ <td><span class="time"><%= format_time(Time.zone.parse(worker.started)) %></span></td>
29
+ <td>
30
+ <% if worker.paused? %>
31
+ <span class="time"><%= format_time(Time.zone.parse(worker.paused)) %></span>
32
+ <% else %>
33
+ <span>Not Paused</span>
34
+ <% end %>
35
+ </td>
36
+ <td class='queues'><%= queues.split(',').map { |q| link_to(q, {:action => 'queues', :id => q}, :class => 'queue-tag') }.join('').html_safe %></td>
37
+ <td><%= worker.processed %></td>
38
+ <td><%= worker.failed %></td>
39
+ <td class='process'>
40
+ <% data = worker.processing || {} %>
41
+ <% if data['queue'] %>
42
+ <code><%= data['payload']['class'] %></code>
43
+ <small><%= link_to(format_time(Time.zone.parse(data['run_at'])), {:action => 'working', :id => worker.to_s.gsub(/\./, '_')}, :class => "queue time") %></small>
44
+ <br>
45
+ <small><%= worker.overview_message %></small>
46
+ <% else %>
47
+ <span class='waiting'>Waiting for a job...</span>
48
+ <% end %>
49
+ </td>
50
+ </tr>
51
+ </table>
52
+
53
+ <% elsif params[:id] %>
54
+
55
+ <h1>Worker doesn't exist</h1>
56
+
57
+ <% else %>
58
+
59
+ <h1 class='wi'><%= pluralize resque.workers.size, 'Worker' %></h1>
60
+ <p class='intro'>The workers listed below are all registered as active on your system.</p>
61
+ <table class='workers'>
62
+ <tr>
63
+ <th>&nbsp;</th>
64
+ <th>Where (ip):pid:thread:path</th>
65
+ <th>Queues</th>
66
+ <th>Processing</th>
67
+ <th>&nbsp;</th>
68
+ </tr>
69
+ <% upid = '' %>
70
+ <% for worker in (workers = resque.workers.sort_by { |w| w.to_s }) %>
71
+ <tr class="<%= state = worker.state %>">
72
+ <td class='icon'>
73
+ <img src="<%="/assets/resque_manager/#{state}" %>.png" alt="<%= state %>" title="<%= state %>"></td>
74
+
75
+ <% host, pid, thread, path, queues = worker.to_s.split(':') %>
76
+ <td class='where'><%= link_to("#{host}:#{pid}:#{thread}:#{path}", :action => 'workers', :id => worker.to_s.gsub(/\./, '_')) %></td>
77
+ <td class='queues'><%= queues.split(',').map { |q| link_to(q, {:action => 'queues', :id => q}, :class => 'queue-tag') }.join('').html_safe %></td>
78
+
79
+ <td class='process'>
80
+ <% data = worker.processing || {} %>
81
+ <% if data['queue'] %>
82
+ <code><%= data['payload']['class'] %></code>
83
+ <small><%= link_to(format_time(Time.zone.parse(data['run_at'])), {:action => 'working', :id => worker.to_s.gsub(/\./, '_')}, :class => "queue time") %></small>
84
+ <br/>
85
+ <small><%= worker.overview_message %></small>
86
+ <% else %>
87
+ <span class='waiting'>Waiting for a job...</span>
88
+ <% end %>
89
+ </td>
90
+ <td>
91
+ <% if upid != pid %>
92
+ <%= button_to "Stop", {:controller=>'resque', :action=> 'stop_worker', :worker => worker.to_s}, :class => 'clear-failed', :title => "This will stop all workers on #{host} in pid #{pid}: #{worker.workers_in_pid.collect { |w| w.to_s }.join(', ')}", :method => :post %>
93
+ <% if worker.paused? %>
94
+ <%= button_to "Unpause", {:controller=>'resque', :action=> 'continue_worker', :worker => worker.to_s}, :class => 'clear-failed', :title => "This will unpause all workers on #{host} in pid #{pid}: #{worker.workers_in_pid.collect { |w| w.to_s }.join(', ')}", :method => :post %>
95
+ <% else %>
96
+ <%= button_to "Pause", {:controller=>'resque', :action=> 'pause_worker', :worker => worker.to_s}, :class => 'clear-failed', :title => "This will pause all workers on #{host} in pid #{pid}: #{worker.workers_in_pid.collect { |w| w.to_s }.join(', ')}", :method => :post %>
97
+ <% end %>
98
+ <%= button_to "Restart", {:controller=>'resque', :action=> 'restart_worker', :worker => worker.to_s}, :class => 'clear-failed', :title => "This will restart all workers on #{host} in pid #{pid}: #{worker.workers_in_pid.collect { |w| w.to_s }.join(', ')}", :method => :post %>
99
+ <% upid = pid %>
100
+ <% end %>
101
+ </td>
102
+ </tr>
103
+ <% end %>
104
+ <% if workers.empty? %>
105
+ <tr>
106
+ <td colspan='5' class='no-data'>There are no registered workers</td>
107
+ </tr>
108
+ <% end %>
109
+ </table>
110
+ <%= poll %>
111
+ <br/>
112
+ <hr/>
113
+ <h1 class='wi'>Start New Workers</h1>
114
+ <%= form_tag :action => 'start_worker' do -%>
115
+ <ul class='new_worker'>
116
+ <li>
117
+ <dl>
118
+ <dt>Queue(s)</dt>
119
+ <dd><%= text_field_tag :queues, nil, :size => 125 %>
120
+ <br/> Prefix each worker with a '#', comma separate the list of queues you want each worker to monitor.
121
+ No Spaces. #queue1,queue2#queue3#queue2 will produce 3 workers in 3 threads.
122
+ </dd>
123
+ <dt>Host(s)/IP(s)</dt>
124
+ <dd><%= text_field_tag :hosts, nil, :size => 125 %>
125
+ <br/> Comma separate the IP address of the servers where you want your worker to run.
126
+ </dd>
127
+ <% if ResqueManager.applications.present? %>
128
+ <dt>Application</dt>
129
+ <dd><%= select_tag :application_path, options_for_select(ResqueManager.applications.to_a), :include_blank => true %>
130
+ <br/> The application where the workers are if not in the same application as the UI.
131
+ </dd>
132
+ <% end %>
133
+ <dt><%= submit_tag "Start", :id => "submit" %></dt>
134
+ </dl>
135
+ </li>
136
+ </ul>
137
+ <% end -%>
138
+ <% end %>
@@ -0,0 +1,69 @@
1
+ <% if params[:id] && (worker = find_worker(params[:id])) && !worker.job.empty? %>
2
+ <h1><%= worker %>'s job</h1>
3
+
4
+ <table>
5
+ <tr>
6
+ <th>&nbsp;</th>
7
+ <th>Where (ip):pid:thread:path</th>
8
+ <th>Queue</th>
9
+ <th>Started</th>
10
+ <th>Class</th>
11
+ <th>Args</th>
12
+ </tr>
13
+ <tr>
14
+ <td><img src="<%='assets/resque_manager/working.png' %>" alt="working" title="working"></td>
15
+ <% host, pid,thread, path, _ = worker.to_s.split(':') %>
16
+ <td><%= link_to("#{host}:#{pid}:#{thread}:#{path}", {:action => 'workers', :id => worker.to_s.gsub(/\./,'_')}) %></td>
17
+ <% data = worker.job %>
18
+ <% queue = data['queue'] %>
19
+ <td><%= link_to(queue, {:action => 'queues', :id => queue}, :class => 'queue') %></td>
20
+ <td><span class="time"><%= format_time(Time.zone.parse(data['run_at'].to_s)) %></span></td>
21
+ <td>
22
+ <code><%= data['payload']['class'] %></code>
23
+ </td>
24
+ <td><%= data['payload']['args'].inspect.html_safe %></td>
25
+ </tr>
26
+ </table>
27
+
28
+ <% else %>
29
+
30
+ <% workers = resque.working %>
31
+ <h1 class='wi'><%= workers.size %> of <%= resque.workers.size %> Workers Working</h1>
32
+ <p class='intro'>The list below contains all workers which are currently running a job.</p>
33
+ <table class='workers'>
34
+ <tr>
35
+ <th>&nbsp;</th>
36
+ <th>Where (ip):pid:thread:path</th>
37
+ <th>Queue</th>
38
+ <th>Processing</th>
39
+ </tr>
40
+ <% if workers.empty? %>
41
+ <tr>
42
+ <td colspan="4" class='no-data'>Nothing is happening right now...</td>
43
+ </tr>
44
+ <% end %>
45
+
46
+ <% for worker in workers.sort_by { |w| w.job['run_at'].to_s } %>
47
+ <% job = worker.job %>
48
+ <tr>
49
+ <td class='icon'><img src="<%="/assets/resque_manager/#{state = worker.state}" %>.png" alt="<%= state %>" title="<%= state %>"></td>
50
+ <% host, pid, thread, path, queues = worker.to_s.split(':') %>
51
+ <td class='where'><%= link_to("#{host}:#{pid}:#{thread}:#{path}", {:action => 'workers', :id => worker.to_s.gsub(/\./,'_')}) %></td>
52
+ <td class='queues queue'>
53
+ <%= link_to(job['queue'], {:action => 'queues', :id => job['queue']}, :class => 'queue-tag') %>
54
+ </td>
55
+ <td class='process'>
56
+ <% if job['queue'] %>
57
+ <code><%= job['payload']['class'] %></code>
58
+ <small><%= link_to(format_time(Time.zone.parse(job['run_at'].to_s)), {:action => 'working', :id => worker.to_s.gsub(/\./,'_')}, :class => 'queue time') %></small>
59
+ <br/>
60
+ <small><%=worker.overview_message%></small>
61
+ <% else %>
62
+ <span class='waiting'>Waiting for a job...</span>
63
+ <% end %>
64
+ </td>
65
+ </tr>
66
+ <% end %>
67
+ </table>
68
+
69
+ <% end %>
@@ -0,0 +1,41 @@
1
+ <div class="cleaner">
2
+ <div class="title clearfix">
3
+ <h1>Job Classes Failed</h1>
4
+ </div>
5
+
6
+ <table class="class_list">
7
+ <tr>
8
+ <th>Class</th>
9
+ <th>Failed</th>
10
+ <th>In last 1 hour</th>
11
+ <th>In last 3 hours</th>
12
+ <th>In last 24 hours</th>
13
+ <th>In last 3 days</th>
14
+ <th>In last 7 days</th>
15
+ </tr>
16
+ <% @stats.each do |klass, count| %>
17
+ <tr>
18
+ <td><%= klass %></td>
19
+ <td class="number"><a href="cleaner_list?c=<%= klass %>"><%= count["total"] %></a></td>
20
+ <td class="number"><a href="cleaner_list?c=<%= klass %>&f=1"><%= count["1h"] %></a></td>
21
+ <td class="number"><a href="cleaner_list?c=<%= klass %>&f=3"><%= count["3h"] %></a></td>
22
+ <td class="number"><a href="cleaner_list?c=<%= klass %>&f=24"><%= count["1d"] %></a></td>
23
+ <td class="number"><a href="cleaner_list?c=<%= klass %>&f=72"><%= count["3d"] %></a></td>
24
+ <td class="number"><a href="cleaner_list?c=<%= klass %>&f=168"><%= count["7d"] %></a></td>
25
+ </tr>
26
+ <% end %>
27
+ <tr class="total">
28
+ <td>Total</td>
29
+ <td class="number"><a href="cleaner_list"><%= @total["total"] %></a></td>
30
+ <td class="number"><a href="cleaner_list?f=1"><%= @total["1h"] %></a></td>
31
+ <td class="number"><a href="cleaner_list?f=3"><%= @total["3h"] %></a></td>
32
+ <td class="number"><a href="cleaner_list?f=24"><%= @total["1d"] %></a></td>
33
+ <td class="number"><a href="cleaner_list?f=72"><%= @total["3d"] %></a></td>
34
+ <td class="number"><a href="cleaner_list?f=168"><%= @total["7d"] %></a></td>
35
+ </tr>
36
+ </table>
37
+
38
+ <% if @cleaner.limiter.on? %>
39
+ <%= render :partial => 'limiter' %>
40
+ <% end %>
41
+ </div>
@@ -0,0 +1,6 @@
1
+ <div class="cleaner">
2
+ <p class="message">Processed <%= @count %> jobs.</p>
3
+ <p class="back_to_list">
4
+ <a href="<%=@link_url%>">Back to List</a>
5
+ </p>
6
+ </div>
@@ -0,0 +1,172 @@
1
+ <!-- Many code was copied from failed.erb of the original resque -->
2
+ <div class="cleaner">
3
+ <div class="title clearfix">
4
+ <h1>Failed Jobs</h1>
5
+ </div>
6
+
7
+ <div class="clearfix">
8
+ <div class="control_panel sub_header">
9
+ <form method="get">
10
+ <span class="class_filter">
11
+ Class: <%= class_filter("filter_class","c",@klasses,@klass)%>
12
+ </span>
13
+ <span class="exception_filter">
14
+ Exception: <%= exception_filter("filter_class","ex",@exceptions,@exception)%>
15
+ </span>
16
+ <span class="time_filter">
17
+ From: <%= time_filter("filter_from","f",@from)%>
18
+ </span>
19
+ <span class="time_filter">
20
+ To: <%= time_filter("filter_to","t",@to)%>
21
+ </span>
22
+ <input type="submit" value="Filter" />
23
+ </form>
24
+ </div>
25
+ </div>
26
+
27
+ <% if @count > 0 %>
28
+ <div class="clearfix">
29
+ <div class="control_panel sub_header">
30
+ <%= form_tag('cleaner_exec', id: 'exec') do %>
31
+ <input type="hidden" name="c" value="<%=@klass%>" />
32
+ <input type="hidden" name="f" value="<%=@from%>" />
33
+ <input type="hidden" name="t" value="<%=@to%>" />
34
+ <input type="hidden" name="p" value="<%=@paginate.page%>" />
35
+ <input type="hidden" name="ex" value="<%=@exception%>" />
36
+ <select id="form_action" name="form_action">
37
+ <option id="default_option" value="" selected="selected">-- Select Action --</option>
38
+ <option value="clear">Clear</option>
39
+ <option value="retry_and_clear">Retry and Clear</option>
40
+ <option value="retry">Retry</option>
41
+ </select>
42
+ <a href="#" id="select_all">select all</a>
43
+ <a href="#" id="reset_all">reset</a>
44
+
45
+ <% if @paginate.max_page > 1 %>
46
+ <input type="checkbox" name="select_all_pages" value="1" id="select_all_pages" />Select all <%=@count%> jobs
47
+ <% end %>
48
+ <input type="hidden" name="sha1" id="sha1_list" />
49
+
50
+ <% end -%>
51
+ </div>
52
+ </div>
53
+ <% end %>
54
+
55
+ <% start = 0 %>
56
+ <% failed = @paginate.paginated_jobs%>
57
+ <% index = 0 %>
58
+ <% date_format = "%Y/%m/%d %T %z" %>
59
+
60
+ <% if @paginate.max_page > 0 %>
61
+ <%= render :partial => 'paginate' %>
62
+ <ul class='failed'>
63
+ <%for job in failed%>
64
+ <% index += 1 %>
65
+ <li>
66
+ <dl>
67
+ <% if job.nil? %>
68
+ <dt>Error</dt>
69
+ <dd>Job <%= index%> could not be parsed; perhaps it contains invalid JSON?</dd>
70
+ <% else %>
71
+ <dt>
72
+ <input type="checkbox" id="<%=Digest::SHA1.hexdigest job.to_json %>" />
73
+ </dt>
74
+ <dd>&nbsp;</dd>
75
+ <dt>Worker</dt>
76
+ <dd>
77
+ <a href="<%= u(:workers, job['worker']) %>"><%= job['worker'].split(':')[0...2].join(':') %></a> on <b class='queue-tag'><%= job['queue'] %></b > at <b><span class="time"><%= Time.parse(job['failed_at']).strftime(date_format) %></span></b>
78
+ <% if job['retried_at'] %>
79
+ <div class='retried'>
80
+ Retried <b><span class="time"><%= Time.parse(job['retried_at']).strftime(date_format) %></span></b>
81
+ </div>
82
+ <% end %>
83
+ </dd>
84
+ <dt>Class</dt>
85
+ <dd><code><%= job['payload'] ? job['payload']['class'] : 'nil' %></code></dd>
86
+ <dt>Arguments</dt>
87
+ <dd><pre><%= job['payload'] ? show_args(job['payload']['args']).html_safe : 'nil' %></pre></dd>
88
+ <dt>Exception</dt>
89
+ <dd><code><%= job['exception'] %></code></dd>
90
+ <dt>Error</dt>
91
+ <dd class='error'>
92
+ <% if job['backtrace'].present? %>
93
+ <a href="#" class="backtrace"><%= h(job['error']) %></a>
94
+ <pre style='display:none'><%= job['backtrace'].join("\n").html_safe %></pre>
95
+ <% else %>
96
+ <%= job['error'].to_s.html_safe %>
97
+ <% end %>
98
+ </dd>
99
+ <% end %>
100
+ </dl>
101
+ <div class='r'>
102
+ </div>
103
+ </li>
104
+ <%end%>
105
+ </ul>
106
+ <%= render :partial => 'paginate' %>
107
+ <% else %>
108
+ Clean!
109
+ <% end %>
110
+ </div>
111
+
112
+ <script>
113
+ $(document).ready(function(){
114
+ $('#select_all_pages').click(function() {
115
+ updateCheckboxStaus();
116
+ });
117
+
118
+ $('#select_all').click(function() {
119
+ if (!$(this).hasClass('disabled')) {
120
+ $('.failed input').attr('checked','checked');
121
+ }
122
+ return false;
123
+ });
124
+ $('#reset_all').click(function() {
125
+ if (!$(this).hasClass('disabled')) {
126
+ $('.failed input').removeAttr('checked');
127
+ }
128
+ return false;
129
+ });
130
+
131
+ $('#form_action').change( function() {
132
+ if ($('#form_action option:selected').val()=='') return;
133
+
134
+ if ($('#select_all_pages:checked, .failed input:checked').length==0) {
135
+ alert('Please select jobs.');
136
+ $('#default_option').attr('selected','selected');
137
+ return false;
138
+ }
139
+
140
+ if (!confirm('Do you really want to proceed?')) {
141
+ $('#default_option').attr('selected','selected');
142
+ return false;
143
+ }
144
+
145
+ if ($('#select_all_pages:checked').length==0) {
146
+ setSha1();
147
+ }
148
+ $('#exec').submit();
149
+ });
150
+ });
151
+
152
+ function setSha1() {
153
+ var sha1 = "";
154
+ $('.failed input:checked').each( function() {
155
+ if (sha1.length>0) sha1 += ",";
156
+ sha1 += $(this).attr("id");
157
+ });
158
+
159
+ $('#sha1_list').val(sha1);
160
+ }
161
+
162
+ function updateCheckboxStaus() {
163
+ if ($('#select_all_pages:checked').length==1) {
164
+ $('#exec a').addClass('disabled');
165
+ $('.failed input').attr('disabled','disabled');
166
+ } else {
167
+ $('#exec a').removeClass('disabled');
168
+ $('.failed input').removeAttr('disabled');
169
+ }
170
+ };
171
+
172
+ </script>
@@ -0,0 +1,35 @@
1
+ <h1>Delayed Jobs</h1>
2
+
3
+ <p class='intro'>
4
+ This list below contains the timestamps for scheduled delayed jobs.
5
+ </p>
6
+
7
+ <p class='sub'>
8
+ Showing <%= start = params[:start].to_i %> to <%= start + 20 %> of <b><%=size = resque.delayed_queue_schedule_size %></b> timestamps
9
+ </p>
10
+
11
+ <table>
12
+ <tr>
13
+ <th>Timestamp</th>
14
+ <th>Job count</th>
15
+ <th>Class</th>
16
+ <th>Args</th>
17
+ </tr>
18
+ <% resque.delayed_queue_peek(start, start+20).each do |timestamp| %>
19
+ <tr>
20
+ <td><a href="<%= url "delayed/#{timestamp}" %>"><%= format_time(Time.at(timestamp)) %></a></td>
21
+ <td><%= delayed_timestamp_size = resque.delayed_timestamp_size(timestamp) %></td>
22
+ <% job = resque.delayed_timestamp_peek(timestamp, 0, 1).first %>
23
+ <td>
24
+ <% if job && delayed_timestamp_size == 1 %>
25
+ <%= h(job['class']) %>
26
+ <% else %>
27
+ <a href="<%= url "delayed/#{timestamp}" %>">see details</a>
28
+ <% end %>
29
+ </td>
30
+ <td><%= h(job['args'].inspect) if job && delayed_timestamp_size == 1 %></td>
31
+ </tr>
32
+ <% end %>
33
+ </table>
34
+
35
+ <%= render(:partial => 'next_more', :locals => {:start => start, :size => size}) %>
@@ -0,0 +1,26 @@
1
+ <% timestamp = params[:timestamp].to_i %>
2
+
3
+ <h1>Delayed jobs scheduled for <%= format_time(Time.at(timestamp)) %></h1>
4
+
5
+ <p class='sub'>Showing <%= start = params[:start].to_i %> to <%= start + 20 %> of <b><%=size = resque.delayed_timestamp_size(timestamp)%></b> jobs</p>
6
+
7
+ <table class='jobs'>
8
+ <tr>
9
+ <th>Class</th>
10
+ <th>Args</th>
11
+ </tr>
12
+ <% jobs = resque.delayed_timestamp_peek(timestamp, start, 20) %>
13
+ <% jobs.each do |job| %>
14
+ <tr>
15
+ <td class='class'><%= job['class'] %></td>
16
+ <td class='args'><%= job['args'].inspect.html_safe %></td>
17
+ </tr>
18
+ <% end %>
19
+ <% if jobs.empty? %>
20
+ <tr>
21
+ <td class='no-data' colspan='2'>There are no pending jobs scheduled for this time.</td>
22
+ </tr>
23
+ <% end %>
24
+ </table>
25
+
26
+ <%= partial :next_more, :start => start, :size => size %>
@@ -0,0 +1 @@
1
+ <h1 style="font-size:110%;font-family:Arial, sans-serif;"><%= error %></h1>
@@ -0,0 +1,4 @@
1
+ <%= render(:partial => 'queues', :locals => {:partial => true}) %>
2
+ <hr />
3
+ <%= render(:partial => 'working') %>
4
+ <%= poll %>