delayed_job_web 1.2.10 → 1.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.markdown +51 -8
- data/delayed_job_web.gemspec +5 -4
- data/lib/delayed_job_web/application/app.rb +32 -10
- data/lib/delayed_job_web/application/public/javascripts/jquery.relatize_date.js +5 -6
- data/lib/delayed_job_web/application/views/layout.erb +6 -0
- data/lib/delayed_job_web/application/views/overview.erb +21 -0
- data/lib/delayed_job_web/application/views/pending.erb +6 -4
- data/test/lib/delayed_job_web/application/test_app.rb +23 -2
- data/test/support/delayed_job_fake.rb +9 -1
- metadata +17 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 49f284c7a691aa183dbda07f8cd9f3d6e33f9f6e0e79985f17f6ef8c67d5e71d
|
4
|
+
data.tar.gz: 45641da1cdb9a8d50c883bf137096a7c2c63f01eaac96ba10e89ec8f0d1ca615
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60aae9c66697be21e1f2eda5049579d132310b3238c45ea72867fb9a25709d08cad82fae96eba3ddea34f6b46a5a0ab9c2da8d2a8031d1d5b606a4659707eaec
|
7
|
+
data.tar.gz: b55549b06221984a1e3f904ebb352978ade7eef9cc1576f35d00f3d0de0652490dd2abb05e833d41d4e43636e8a2a2eda993bec1d8c183a801d0cde242e15001
|
data/README.markdown
CHANGED
@@ -7,15 +7,16 @@ activerecord.
|
|
7
7
|
|
8
8
|
Some features:
|
9
9
|
|
10
|
-
* Easily view
|
11
|
-
* Queue any single job
|
12
|
-
* Remove a failed job
|
10
|
+
* Easily view enqueued, working, pending, and failed jobs.
|
11
|
+
* Queue any single job or all pending jobs to run immediately.
|
12
|
+
* Remove a failed job or easily remove all failed jobs.
|
13
13
|
* Watch delayed_job operation with live ajax polling.
|
14
|
-
* Filter delayed_jobs by queue
|
14
|
+
* Filter delayed_jobs by queue names (comma separated values in the input filter).
|
15
|
+
* Reset all queue filters by clicking the reset button.
|
15
16
|
|
16
|
-
The interface (
|
17
|
+
The interface (yeah, a ripoff of resque-web):
|
17
18
|
|
18
|
-
![Screen shot](
|
19
|
+
![Screen shot](./delayed_job_web.png)
|
19
20
|
|
20
21
|
|
21
22
|
Quick Start For Rails 3 and 4 Applications
|
@@ -37,7 +38,7 @@ Add the following route to your application for accessing the interface,
|
|
37
38
|
and retrying failed jobs.
|
38
39
|
|
39
40
|
```ruby
|
40
|
-
match "/delayed_job" => DelayedJobWeb, :anchor => false, via
|
41
|
+
match "/delayed_job" => DelayedJobWeb, :anchor => false, :via => [:get, :post]
|
41
42
|
```
|
42
43
|
|
43
44
|
You probably want to password protect the interface, an easy way is to add something like this your config.ru file
|
@@ -45,13 +46,38 @@ You probably want to password protect the interface, an easy way is to add somet
|
|
45
46
|
```ruby
|
46
47
|
if Rails.env.production?
|
47
48
|
DelayedJobWeb.use Rack::Auth::Basic do |username, password|
|
48
|
-
|
49
|
+
ActiveSupport::SecurityUtils.variable_size_secure_compare('username', username) &&
|
50
|
+
ActiveSupport::SecurityUtils.variable_size_secure_compare('password', password)
|
49
51
|
end
|
50
52
|
end
|
51
53
|
```
|
52
54
|
|
53
55
|
`delayed_job_web` runs as a Sinatra application within the rails application. Visit it at `/delayed_job`.
|
54
56
|
|
57
|
+
|
58
|
+
## Authenticating with Devise and Warden
|
59
|
+
|
60
|
+
This can be accomplished in the routes.rb file using an `authenticated` callback. Note, do not use an `authenticate` callback as this forces an authentication check and redirects can be screwy, [see here](http://excid3.com/blog/rails-tip-5-authenticated-root-and-dashboard-routes-with-devise/) for more information.
|
61
|
+
|
62
|
+
A simple user check looks like this:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
|
66
|
+
authenticated :user do
|
67
|
+
mount DelayedJobWeb, at: "/delayed_job"
|
68
|
+
end
|
69
|
+
|
70
|
+
```
|
71
|
+
But you probably want to check for administrator permissions:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
|
75
|
+
authenticated :user, -> user { user.admin? } do
|
76
|
+
mount DelayedJobWeb, at: "/delayed_job"
|
77
|
+
end
|
78
|
+
|
79
|
+
```
|
80
|
+
|
55
81
|
## Serving static assets
|
56
82
|
|
57
83
|
If you mount the app on another route, you may encounter the CSS not working anymore. To work around this you can leverage a special HTTP header. Install it, activate it and configure it -- see below.
|
@@ -75,6 +101,19 @@ Rails' will need to be configured to `config.action_dispatch.x_sendfile_header =
|
|
75
101
|
|
76
102
|
Lighty is more `X-Sendfile`, like [outlined](http://redmine.lighttpd.net/projects/1/wiki/X-LIGHTTPD-send-file) in their wiki.
|
77
103
|
|
104
|
+
Configuration
|
105
|
+
-------------
|
106
|
+
|
107
|
+
The following settings can be changed using the `.set` method in your configu.ru. For example:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
DelayedJobWeb.set(:allow_requeue_pending, false)
|
111
|
+
```
|
112
|
+
|
113
|
+
* **`allow_requeue_pending`** (default: `true`)
|
114
|
+
|
115
|
+
Controls whether the 'Enqueue all immediately' button is available on the list of Pending jobs. Hiding this button can be useful if you have jobs set to run in the future and you don't want to accidentally run them immediately.
|
116
|
+
|
78
117
|
|
79
118
|
Contributing
|
80
119
|
------------
|
@@ -104,6 +143,10 @@ Author
|
|
104
143
|
|
105
144
|
Erick Schmitt - [@ejschmitt][1]
|
106
145
|
|
146
|
+
Maintained by Andy Atkinson - [@andatki][2]
|
147
|
+
|
148
|
+
Get in touch if you'd like to take over maintenance!
|
107
149
|
|
108
150
|
[0]: https://github.com/defunkt/resque
|
109
151
|
[1]: http://twitter.com/ejschmitt
|
152
|
+
[2]: http://twitter.com/andatki
|
data/delayed_job_web.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
2
|
gem.name = "delayed_job_web"
|
3
|
-
gem.version = "1.
|
3
|
+
gem.version = "1.4.4"
|
4
4
|
gem.author = "Erick Schmitt"
|
5
5
|
gem.email = "ejschmitt@gmail.com"
|
6
6
|
gem.homepage = "https://github.com/ejschmitt/delayed_job_web"
|
@@ -23,9 +23,10 @@ Gem::Specification.new do |gem|
|
|
23
23
|
"README.markdown"
|
24
24
|
]
|
25
25
|
|
26
|
-
gem.add_runtime_dependency "sinatra",
|
27
|
-
gem.add_runtime_dependency "
|
28
|
-
gem.add_runtime_dependency "
|
26
|
+
gem.add_runtime_dependency "sinatra", [">= 1.4.4"]
|
27
|
+
gem.add_runtime_dependency "rack-protection", [">= 1.5.5"]
|
28
|
+
gem.add_runtime_dependency "activerecord", ["> 3.0.0"]
|
29
|
+
gem.add_runtime_dependency "delayed_job", ["> 2.0.3"]
|
29
30
|
|
30
31
|
gem.add_development_dependency "minitest", ["~> 4.2"]
|
31
32
|
gem.add_development_dependency "rack-test", ["~> 0.6"]
|
@@ -9,6 +9,8 @@ class DelayedJobWeb < Sinatra::Base
|
|
9
9
|
set :public_folder, File.expand_path('../public', __FILE__)
|
10
10
|
set :views, File.expand_path('../views', __FILE__)
|
11
11
|
|
12
|
+
set :allow_requeue_pending, true
|
13
|
+
|
12
14
|
# Enable sessions so we can use CSRF protection
|
13
15
|
enable :sessions
|
14
16
|
|
@@ -38,17 +40,31 @@ class DelayedJobWeb < Sinatra::Base
|
|
38
40
|
end
|
39
41
|
|
40
42
|
def per_page
|
41
|
-
20
|
43
|
+
params[:per_page].to_i > 0 ? params[:per_page].to_i : 20
|
42
44
|
end
|
43
45
|
|
44
46
|
def url_path(*path_parts)
|
45
47
|
url = [ path_prefix, path_parts ].join("/").squeeze('/')
|
46
|
-
url += "?queues=#{@queues.join(",")}" unless @queues.empty?
|
48
|
+
url += "?queues=#{CGI.escape(@queues.join(","))}" unless @queues.empty?
|
47
49
|
url
|
48
50
|
end
|
49
51
|
|
50
52
|
alias_method :u, :url_path
|
51
53
|
|
54
|
+
def queue_path(queue)
|
55
|
+
with_queue(queue) do
|
56
|
+
url_path(:overview)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def with_queue(queue, &block)
|
61
|
+
aux_queues = @queues
|
62
|
+
@queues = Array(queue)
|
63
|
+
result = block.call
|
64
|
+
@queues = aux_queues
|
65
|
+
result
|
66
|
+
end
|
67
|
+
|
52
68
|
def h(text)
|
53
69
|
Rack::Utils.escape_html(text)
|
54
70
|
end
|
@@ -106,6 +122,7 @@ class DelayedJobWeb < Sinatra::Base
|
|
106
122
|
get "/#{page}" do
|
107
123
|
@jobs = delayed_jobs(page.to_sym, @queues).order('created_at desc, id desc').offset(start).limit(per_page)
|
108
124
|
@all_jobs = delayed_jobs(page.to_sym, @queues)
|
125
|
+
@allow_requeue_pending = settings.allow_requeue_pending
|
109
126
|
erb page.to_sym
|
110
127
|
end
|
111
128
|
end
|
@@ -115,22 +132,27 @@ class DelayedJobWeb < Sinatra::Base
|
|
115
132
|
redirect back
|
116
133
|
end
|
117
134
|
|
118
|
-
|
119
|
-
|
120
|
-
delayed_jobs(
|
121
|
-
redirect back
|
135
|
+
post "/requeue/pending" do
|
136
|
+
if settings.allow_requeue_pending
|
137
|
+
delayed_jobs(:pending, @queues).update_all(:run_at => Time.now, :failed_at => nil)
|
122
138
|
end
|
139
|
+
redirect back
|
140
|
+
end
|
141
|
+
|
142
|
+
post "/requeue/failed" do
|
143
|
+
delayed_jobs(:failed, @queues).update_all(:run_at => Time.now, :failed_at => nil)
|
144
|
+
redirect back
|
123
145
|
end
|
124
146
|
|
125
147
|
post "/requeue/:id" do
|
126
148
|
job = delayed_job.find(params[:id])
|
127
|
-
job.
|
149
|
+
job.update(run_at: Time.now, failed_at: nil)
|
128
150
|
redirect back
|
129
151
|
end
|
130
152
|
|
131
153
|
post "/reload/:id" do
|
132
154
|
job = delayed_job.find(params[:id])
|
133
|
-
job.
|
155
|
+
job.update(run_at: Time.now, failed_at: nil, locked_by: nil, locked_at: nil, last_error: nil, attempts: 0)
|
134
156
|
redirect back
|
135
157
|
end
|
136
158
|
|
@@ -145,7 +167,7 @@ class DelayedJobWeb < Sinatra::Base
|
|
145
167
|
rel =
|
146
168
|
case type
|
147
169
|
when :working
|
148
|
-
rel.where('locked_at IS NOT NULL')
|
170
|
+
rel.where('locked_at IS NOT NULL AND failed_at IS NULL')
|
149
171
|
when :failed
|
150
172
|
rel.where('last_error IS NOT NULL')
|
151
173
|
when :pending
|
@@ -170,7 +192,7 @@ class DelayedJobWeb < Sinatra::Base
|
|
170
192
|
@partial = false
|
171
193
|
end
|
172
194
|
|
173
|
-
%w
|
195
|
+
%w[overview enqueued working pending failed stats].each do |page|
|
174
196
|
get "/#{page}.poll" do
|
175
197
|
show_for_polling(page)
|
176
198
|
end
|
@@ -77,17 +77,17 @@
|
|
77
77
|
return daysfrom + " days from now";
|
78
78
|
}
|
79
79
|
} else if (delta < -(48*60*60)) {
|
80
|
-
return '
|
80
|
+
return '2 days from now';
|
81
81
|
} else if (delta < -(24*60*60)) {
|
82
|
+
return '1 day from now';
|
83
|
+
} else if (delta < -(120*60)) {
|
82
84
|
return 'about ' + parseInt(Math.abs(delta / 3600)).toString() +
|
83
85
|
' hours from now';
|
84
|
-
} else if (delta < -(120*60)) {
|
85
|
-
return 'about an hour from now';
|
86
86
|
} else if (delta < -(45*60)) {
|
87
|
+
return 'about an hour from now';
|
88
|
+
} else if (delta < -60) {
|
87
89
|
return parseInt(Math.abs(delta / 60)).toString()
|
88
90
|
+ ' minutes from now';
|
89
|
-
} else if (delta < -60) {
|
90
|
-
return 'about a minute from now';
|
91
91
|
} else if (delta < 0) {
|
92
92
|
return 'less than a minute from now';
|
93
93
|
} else if (delta < 60) {
|
@@ -102,7 +102,6 @@
|
|
102
102
|
return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';
|
103
103
|
} else if (delta < (48*60*60)) {
|
104
104
|
return '1 day ago';
|
105
|
-
} else {
|
106
105
|
var days = (parseInt(delta / 86400)).toString();
|
107
106
|
if (days > 5) {
|
108
107
|
var fmt = '%B %d, %Y'
|
@@ -21,6 +21,12 @@
|
|
21
21
|
<input type="submit" value="Filter" />
|
22
22
|
</form>
|
23
23
|
</li>
|
24
|
+
<li>
|
25
|
+
<form method="get" class="header-queues" action="" style="display:inline;">
|
26
|
+
<input name="queues" type="hidden" value="" />
|
27
|
+
<input type="submit" value="Reset" />
|
28
|
+
</form>
|
29
|
+
</li>
|
24
30
|
</ul>
|
25
31
|
</div>
|
26
32
|
<div id="main">
|
@@ -42,4 +42,25 @@
|
|
42
42
|
</td>
|
43
43
|
</tr>
|
44
44
|
</table>
|
45
|
+
|
46
|
+
<table class="overview">
|
47
|
+
<tr>
|
48
|
+
<th>Queue</th>
|
49
|
+
<th>Count</th>
|
50
|
+
</tr>
|
51
|
+
|
52
|
+
<% delayed_jobs(nil).group(:queue).size.each do |queue, count| %>
|
53
|
+
<tr>
|
54
|
+
<td class="status">
|
55
|
+
<a href="<%= queue_path(queue) %>">
|
56
|
+
<%= queue %>
|
57
|
+
</a>
|
58
|
+
</td>
|
59
|
+
<td>
|
60
|
+
<%= count %>
|
61
|
+
</td>
|
62
|
+
</tr>
|
63
|
+
<% end %>
|
64
|
+
</table>
|
65
|
+
|
45
66
|
<%= poll %>
|
@@ -1,9 +1,11 @@
|
|
1
1
|
<h1>Pending</h1>
|
2
2
|
<% if @jobs.any? %>
|
3
|
-
|
4
|
-
<%=
|
5
|
-
|
6
|
-
|
3
|
+
<% if @allow_requeue_pending %>
|
4
|
+
<form action="<%= u('requeue/pending') %>" method="POST">
|
5
|
+
<%= csrf_token_tag %>
|
6
|
+
<input type="submit" value="Enqueue All Immediately"></input>
|
7
|
+
</form>
|
8
|
+
<% end %>
|
7
9
|
<% end %>
|
8
10
|
<p class="sub">
|
9
11
|
The list below contains jobs currently being processed.
|
@@ -35,7 +35,7 @@ class TestDelayedJobWeb < MiniTest::Unit::TestCase
|
|
35
35
|
|
36
36
|
dataset = Minitest::Mock.new
|
37
37
|
where = lambda { | criteria |
|
38
|
-
criteria.must_equal
|
38
|
+
criteria.must_equal :attempts => 0, :locked_at => nil
|
39
39
|
dataset
|
40
40
|
}
|
41
41
|
|
@@ -43,11 +43,32 @@ class TestDelayedJobWeb < MiniTest::Unit::TestCase
|
|
43
43
|
|
44
44
|
Time.stub(:now, time) do
|
45
45
|
Delayed::Job.stub(:where, where) do
|
46
|
-
post "/requeue/
|
46
|
+
post "/requeue/pending", request_data, rack_env
|
47
|
+
last_response.status.must_equal 302
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
dataset.verify
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_requeue_pending_with_requeue_pending_disallowed
|
56
|
+
|
57
|
+
app.set(:allow_requeue_pending, false)
|
58
|
+
|
59
|
+
dataset = Minitest::Mock.new
|
60
|
+
where = lambda { |criteria|
|
61
|
+
dataset
|
62
|
+
}
|
63
|
+
|
64
|
+
Time.stub(:now, time) do
|
65
|
+
Delayed::Job.stub(:where, where) do
|
66
|
+
post "/requeue/pending", request_data, rack_env
|
47
67
|
last_response.status.must_equal 302
|
48
68
|
end
|
49
69
|
end
|
50
70
|
|
71
|
+
# Expect dataset to not have received any method calls.
|
51
72
|
dataset.verify
|
52
73
|
|
53
74
|
end
|
@@ -14,6 +14,14 @@ class Delayed::Job
|
|
14
14
|
def limit(*args)
|
15
15
|
DelayedJobFake.new
|
16
16
|
end
|
17
|
+
|
18
|
+
def size(*args)
|
19
|
+
{}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.group(*args)
|
24
|
+
DelayedJobFake.new
|
17
25
|
end
|
18
26
|
|
19
27
|
def self.where(*args)
|
@@ -31,4 +39,4 @@ class Delayed::Job
|
|
31
39
|
def self.find(*args)
|
32
40
|
DelayedJobFake.new
|
33
41
|
end
|
34
|
-
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delayed_job_web
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Erick Schmitt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.4.4
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rack-protection
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.5.5
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.5.5
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: activerecord
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -152,8 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
166
|
- !ruby/object:Gem::Version
|
153
167
|
version: '0'
|
154
168
|
requirements: []
|
155
|
-
|
156
|
-
rubygems_version: 2.2.2
|
169
|
+
rubygems_version: 3.1.4
|
157
170
|
signing_key:
|
158
171
|
specification_version: 4
|
159
172
|
summary: Web interface for delayed_job inspired by resque
|