que-web 0.7.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +3 -3
- data/CHANGELOG.md +29 -1
- data/README.md +0 -12
- data/docker/Gemfile.lock +7 -7
- data/examples/rack/Gemfile.lock +14 -14
- data/examples/rack/boot.rb +2 -4
- data/examples/rack/config.ru +1 -3
- data/lib/que/web.rb +17 -14
- data/lib/que/web/sql.rb +32 -19
- data/lib/que/web/viewmodels.rb +2 -0
- data/lib/que/web/viewmodels/dashboard.rb +1 -1
- data/lib/que/web/viewmodels/job.rb +13 -5
- data/que-web.gemspec +7 -8
- data/spec/pager_spec.rb +12 -12
- data/spec/que/web_spec.rb +63 -0
- data/spec/viewmodels/dashboard_spec.rb +5 -5
- data/spec/viewmodels/job_list_spec.rb +11 -11
- data/spec/viewmodels/job_spec.rb +23 -10
- data/spec/web_spec.rb +13 -13
- data/web/public/styles/foundation.min.css +1 -1
- data/web/public/styles/normalize.min.css +1 -0
- data/web/views/_navbar.erb +1 -1
- data/web/views/_search.erb +1 -1
- data/web/views/failing.erb +10 -10
- data/web/views/index.erb +1 -1
- data/web/views/layout.erb +7 -7
- data/web/views/running.erb +6 -4
- data/web/views/scheduled.erb +9 -9
- data/web/views/show.erb +11 -8
- metadata +16 -32
- data/web/public/js/foundation.min.js +0 -3651
- data/web/public/js/vendor/fastclick.js +0 -9
- data/web/public/js/vendor/jquery.cookie.js +0 -8
- data/web/public/js/vendor/modernizr.js +0 -8
- data/web/public/js/vendor/placeholder.js +0 -2
- data/web/public/styles/normalize.css +0 -427
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ebaed73a196599d197e408d743f11878983bd41946128b414a761f41212f798b
|
4
|
+
data.tar.gz: cbf8d59327853afaea14ffc79d6b6633bd56c046b64b8b2200ca29251bc4b2ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6674c985452e1bf8c7aaf159b6efd1d0ef3008bb0020abe7625799a422e76246443c953ff5d4eb7676f8bf0cf4a39e1bee71fcdf3ac97bafafd8f9aa292f6c96
|
7
|
+
data.tar.gz: 39c94ab7f64cb5bf20c2e978aa369fd675dde28b058f52ffb4e2af4fec7c91f8d4d14b904b86d0e2f5c35ef02053be68e3b3d1a8edc02aa4d8a1e8941733436f
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,32 @@
|
|
1
|
-
###
|
1
|
+
### 0.9.3 - 2020-06-17
|
2
|
+
#### Added:
|
3
|
+
- Set expired_at=NULL when rescheduling job
|
4
|
+
- Make job search case-insensitive
|
5
|
+
- Allow to search by ActiveJob class name
|
6
|
+
|
7
|
+
### 0.9.2 - 2020-04-24
|
8
|
+
#### Fixed:
|
9
|
+
- Fixed rendering "running" page
|
10
|
+
- Fixed displaying relative time on "failing" page
|
11
|
+
|
12
|
+
### 0.9.1 - 2020-04-01
|
13
|
+
#### Fixed:
|
14
|
+
- Fixed rendering HTML
|
15
|
+
|
16
|
+
### 0.9.0 - 2020-03-31
|
17
|
+
#### Added:
|
18
|
+
- Display real job class when wrapped by ActiveJob
|
19
|
+
- Updated foundation CSS to latest 5.x version
|
20
|
+
- Removed erubis gem dependency
|
21
|
+
|
22
|
+
#### Fixed:
|
23
|
+
- Fixed minitest deprecation warnings
|
24
|
+
|
25
|
+
### 0.8 - 2018-09-21
|
26
|
+
|
27
|
+
#### Compatibility with 1.0.0.beta3 Que:
|
28
|
+
- Changed job_id to id
|
29
|
+
- Removed pg_* attributes
|
2
30
|
|
3
31
|
### 0.7.1 - 2018-03-02
|
4
32
|
|
data/README.md
CHANGED
@@ -43,18 +43,6 @@ require "que/web"
|
|
43
43
|
mount Que::Web => "/que"
|
44
44
|
```
|
45
45
|
|
46
|
-
#### Rails 5.0
|
47
|
-
|
48
|
-
You must use the master branch of Sinatra for `que-web`.
|
49
|
-
In your gemfile:
|
50
|
-
|
51
|
-
```
|
52
|
-
gem 'que-web'
|
53
|
-
gem 'sinatra', git: 'https://github.com/sinatra/sinatra'
|
54
|
-
```
|
55
|
-
|
56
|
-
See https://github.com/sinatra/sinatra/issues/1071
|
57
|
-
|
58
46
|
### Authentication
|
59
47
|
|
60
48
|
#### Devise
|
data/docker/Gemfile.lock
CHANGED
@@ -2,24 +2,24 @@ GEM
|
|
2
2
|
remote: https://rubygems.org/
|
3
3
|
specs:
|
4
4
|
erubis (2.7.0)
|
5
|
-
mustermann (1.0.
|
5
|
+
mustermann (1.0.3)
|
6
6
|
pg (1.0.0)
|
7
|
-
puma (3.
|
7
|
+
puma (3.12.3)
|
8
8
|
que (0.14.2)
|
9
9
|
que-web (0.7.0)
|
10
10
|
erubis
|
11
11
|
que (~> 0.8)
|
12
12
|
sinatra
|
13
|
-
rack (2.0.
|
14
|
-
rack-protection (2.0.
|
13
|
+
rack (2.0.8)
|
14
|
+
rack-protection (2.0.7)
|
15
15
|
rack
|
16
16
|
sequel (5.5.0)
|
17
|
-
sinatra (2.0.
|
17
|
+
sinatra (2.0.7)
|
18
18
|
mustermann (~> 1.0)
|
19
19
|
rack (~> 2.0)
|
20
|
-
rack-protection (= 2.0.
|
20
|
+
rack-protection (= 2.0.7)
|
21
21
|
tilt (~> 2.0)
|
22
|
-
tilt (2.0.
|
22
|
+
tilt (2.0.10)
|
23
23
|
|
24
24
|
PLATFORMS
|
25
25
|
ruby
|
data/examples/rack/Gemfile.lock
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ../..
|
3
3
|
specs:
|
4
|
-
que-web (0.
|
5
|
-
|
6
|
-
que (~> 0.8)
|
4
|
+
que-web (0.9.2)
|
5
|
+
que (~> 1.0.0.beta3)
|
7
6
|
sinatra
|
8
7
|
|
9
8
|
GEM
|
10
9
|
remote: https://rubygems.org/
|
11
10
|
specs:
|
12
|
-
|
13
|
-
|
14
|
-
pg (1.
|
15
|
-
que (0.
|
16
|
-
rack (2.
|
17
|
-
rack-protection (2.0.
|
11
|
+
mustermann (1.1.1)
|
12
|
+
ruby2_keywords (~> 0.0.1)
|
13
|
+
pg (1.2.3)
|
14
|
+
que (1.0.0.beta4)
|
15
|
+
rack (2.2.2)
|
16
|
+
rack-protection (2.0.8.1)
|
18
17
|
rack
|
19
|
-
|
20
|
-
|
18
|
+
ruby2_keywords (0.0.2)
|
19
|
+
sequel (5.31.0)
|
20
|
+
sinatra (2.0.8.1)
|
21
21
|
mustermann (~> 1.0)
|
22
22
|
rack (~> 2.0)
|
23
|
-
rack-protection (= 2.0.
|
23
|
+
rack-protection (= 2.0.8.1)
|
24
24
|
tilt (~> 2.0)
|
25
|
-
tilt (2.0.
|
25
|
+
tilt (2.0.10)
|
26
26
|
|
27
27
|
PLATFORMS
|
28
28
|
ruby
|
@@ -33,4 +33,4 @@ DEPENDENCIES
|
|
33
33
|
sequel
|
34
34
|
|
35
35
|
BUNDLED WITH
|
36
|
-
1.
|
36
|
+
2.1.4
|
data/examples/rack/boot.rb
CHANGED
@@ -7,9 +7,8 @@ require 'securerandom'
|
|
7
7
|
|
8
8
|
Que.logger = Logger.new(STDOUT)
|
9
9
|
Que.logger.level = Logger::INFO
|
10
|
-
Que.connection = Sequel.connect
|
11
|
-
Que.migrate!
|
12
|
-
Que.mode = :async
|
10
|
+
Que.connection = Sequel.connect("postgres://localhost/quewebtest", max_connections: 1)
|
11
|
+
Que.migrate!(version: 4)
|
13
12
|
$stdout.sync = true
|
14
13
|
|
15
14
|
class FailJob < Que::Job
|
@@ -31,4 +30,3 @@ class SlowJob < Que::Job
|
|
31
30
|
sleep 15
|
32
31
|
end
|
33
32
|
end
|
34
|
-
|
data/examples/rack/config.ru
CHANGED
@@ -22,7 +22,7 @@ end
|
|
22
22
|
|
23
23
|
map '/xss' do
|
24
24
|
run lambda { |env|
|
25
|
-
FailJob.enqueue
|
25
|
+
FailJob.enqueue "<script>alert('xss')</script>", {name: "<script>alert('xss')", age: 20, numbers: [10]*50}
|
26
26
|
[200, {}, ['Failing job queued']]
|
27
27
|
}
|
28
28
|
end
|
@@ -41,7 +41,6 @@ map '/slow' do
|
|
41
41
|
}
|
42
42
|
end
|
43
43
|
|
44
|
-
|
45
44
|
map '/delayslow' do
|
46
45
|
run lambda { |env|
|
47
46
|
SlowJob.enqueue 'arg1', {name: 'delayslow', age: 20}, run_at: Time.now + 10
|
@@ -52,4 +51,3 @@ end
|
|
52
51
|
run lambda { |env|
|
53
52
|
[200, {}, ['Hello']]
|
54
53
|
}
|
55
|
-
|
data/lib/que/web.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require "sinatra/base"
|
2
|
-
require "
|
2
|
+
require "cgi"
|
3
3
|
|
4
4
|
module Que
|
5
5
|
class Web < Sinatra::Base
|
@@ -11,7 +11,6 @@ module Que
|
|
11
11
|
set :root, File.expand_path("../../../web", __FILE__)
|
12
12
|
set :public_folder, proc { "#{root}/public" }
|
13
13
|
set :views, proc { File.expand_path("views", root) }
|
14
|
-
set :erb, :escape_html => true
|
15
14
|
|
16
15
|
get "/" do
|
17
16
|
stats = Que.execute SQL[:dashboard_stats], [search]
|
@@ -20,7 +19,7 @@ module Que
|
|
20
19
|
end
|
21
20
|
|
22
21
|
get "/running" do
|
23
|
-
worker_states = search_running Que.
|
22
|
+
worker_states = search_running Que.job_states
|
24
23
|
pager = get_pager worker_states.count
|
25
24
|
@list = Viewmodels::JobList.new(worker_states, pager)
|
26
25
|
erb :running
|
@@ -28,7 +27,7 @@ module Que
|
|
28
27
|
|
29
28
|
get "/failing" do
|
30
29
|
stats = Que.execute SQL[:dashboard_stats], [search]
|
31
|
-
pager = get_pager stats[0][
|
30
|
+
pager = get_pager stats[0][:failing]
|
32
31
|
failing_jobs = Que.execute SQL[:failing_jobs], [pager.page_size, pager.offset, search]
|
33
32
|
@list = Viewmodels::JobList.new(failing_jobs, pager)
|
34
33
|
erb :failing
|
@@ -36,9 +35,8 @@ module Que
|
|
36
35
|
|
37
36
|
get "/scheduled" do
|
38
37
|
stats = Que.execute SQL[:dashboard_stats], [search]
|
39
|
-
pager = get_pager stats[0][
|
38
|
+
pager = get_pager stats[0][:scheduled]
|
40
39
|
scheduled_jobs = Que.execute SQL[:scheduled_jobs], [pager.page_size, pager.offset, search]
|
41
|
-
|
42
40
|
@list = Viewmodels::JobList.new(scheduled_jobs, pager)
|
43
41
|
erb :scheduled
|
44
42
|
end
|
@@ -62,12 +60,10 @@ module Que
|
|
62
60
|
job_id = id.to_i
|
63
61
|
if job_id > 0
|
64
62
|
run_at = Time.now
|
65
|
-
|
66
63
|
updated_rows = Que.execute SQL[:reschedule_job], [job_id, run_at]
|
67
|
-
|
68
64
|
if updated_rows.empty?
|
69
65
|
# Didn't get the advisory lock
|
70
|
-
set_flash "warning", "Job #{job_id} not rescheduled as it was already
|
66
|
+
set_flash "warning", "Job #{job_id} not rescheduled as it was already running"
|
71
67
|
else
|
72
68
|
set_flash "info", "Job #{job_id} rescheduled for #{run_at}"
|
73
69
|
end
|
@@ -105,7 +101,7 @@ module Que
|
|
105
101
|
|
106
102
|
if updated_rows.empty?
|
107
103
|
# Didn't get the advisory lock
|
108
|
-
set_flash "warning", "Job #{job_id} not deleted as it was already
|
104
|
+
set_flash "warning", "Job #{job_id} not deleted as it was already running"
|
109
105
|
else
|
110
106
|
set_flash "info", "Job #{job_id} deleted"
|
111
107
|
end
|
@@ -163,11 +159,11 @@ module Que
|
|
163
159
|
|
164
160
|
def search_running(jobs)
|
165
161
|
return jobs unless search_param
|
166
|
-
jobs.select { |job| job.fetch(
|
162
|
+
jobs.select { |job| job.fetch(:job_class).include? search_param }
|
167
163
|
end
|
168
164
|
|
169
165
|
def search_param
|
170
|
-
sanitised = (params['search'] || '').gsub(/[^0-9a-z:]i
|
166
|
+
sanitised = (params['search'] || '').gsub(/[^0-9a-z:]/i, '')
|
171
167
|
return if sanitised.empty?
|
172
168
|
sanitised
|
173
169
|
end
|
@@ -183,8 +179,8 @@ module Que
|
|
183
179
|
end
|
184
180
|
|
185
181
|
def format_error(job)
|
186
|
-
return unless job.
|
187
|
-
line = job.
|
182
|
+
return unless job.last_error_message
|
183
|
+
line = job.last_error_message.lines.first || ''
|
188
184
|
truncate line, 30
|
189
185
|
end
|
190
186
|
|
@@ -209,6 +205,13 @@ module Que
|
|
209
205
|
hash = session[FLASH_KEY] ||= {}
|
210
206
|
hash[level] = val
|
211
207
|
end
|
208
|
+
|
209
|
+
def html_escape(text)
|
210
|
+
return if text.nil?
|
211
|
+
|
212
|
+
CGI.escape_html(text)
|
213
|
+
end
|
214
|
+
alias h html_escape
|
212
215
|
end
|
213
216
|
helpers Helpers
|
214
217
|
end
|
data/lib/que/web/sql.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
lock_job_sql = <<-SQL.freeze
|
2
|
-
SELECT
|
2
|
+
SELECT id, pg_try_advisory_lock(id) AS locked
|
3
3
|
FROM que_jobs
|
4
|
-
WHERE
|
4
|
+
WHERE id = $1::bigint
|
5
5
|
SQL
|
6
6
|
|
7
7
|
lock_all_failing_jobs_sql = <<-SQL.freeze
|
8
|
-
SELECT
|
8
|
+
SELECT id, pg_try_advisory_lock(id) AS locked
|
9
9
|
FROM que_jobs
|
10
10
|
WHERE error_count > 0
|
11
11
|
SQL
|
12
12
|
|
13
13
|
lock_all_scheduled_jobs_sql = <<-SQL.freeze
|
14
|
-
SELECT
|
14
|
+
SELECT id, pg_try_advisory_lock(id) AS locked
|
15
15
|
FROM que_jobs
|
16
16
|
WHERE error_count = 0
|
17
17
|
SQL
|
@@ -20,11 +20,12 @@ def reschedule_all_jobs_query(scope)
|
|
20
20
|
<<-SQL.freeze
|
21
21
|
WITH target AS (#{scope})
|
22
22
|
UPDATE que_jobs
|
23
|
-
SET run_at = $1::timestamptz
|
23
|
+
SET run_at = $1::timestamptz,
|
24
|
+
expired_at = NULL
|
24
25
|
FROM target
|
25
26
|
WHERE target.locked
|
26
|
-
AND target.
|
27
|
-
RETURNING pg_advisory_unlock(target.
|
27
|
+
AND target.id = que_jobs.id
|
28
|
+
RETURNING pg_advisory_unlock(target.id)
|
28
29
|
SQL
|
29
30
|
end
|
30
31
|
|
@@ -34,8 +35,8 @@ def delete_jobs_query(scope)
|
|
34
35
|
DELETE FROM que_jobs
|
35
36
|
USING target
|
36
37
|
WHERE target.locked
|
37
|
-
AND target.
|
38
|
-
RETURNING pg_advisory_unlock(target.
|
38
|
+
AND target.id = que_jobs.id
|
39
|
+
RETURNING pg_advisory_unlock(target.id)
|
39
40
|
SQL
|
40
41
|
end
|
41
42
|
|
@@ -50,9 +51,10 @@ Que::Web::SQL = {
|
|
50
51
|
SELECT (classid::bigint << 32) + objid::bigint AS job_id
|
51
52
|
FROM pg_locks
|
52
53
|
WHERE locktype = 'advisory'
|
53
|
-
) locks
|
54
|
+
) locks ON (que_jobs.id=locks.job_id)
|
54
55
|
WHERE
|
55
|
-
job_class
|
56
|
+
job_class ILIKE ($1)
|
57
|
+
OR que_jobs.args #>> '{0, job_class}' ILIKE ($1)
|
56
58
|
SQL
|
57
59
|
failing_jobs: <<-SQL.freeze,
|
58
60
|
SELECT que_jobs.*
|
@@ -61,8 +63,13 @@ Que::Web::SQL = {
|
|
61
63
|
SELECT (classid::bigint << 32) + objid::bigint AS job_id
|
62
64
|
FROM pg_locks
|
63
65
|
WHERE locktype = 'advisory'
|
64
|
-
) locks
|
65
|
-
WHERE locks.job_id IS NULL
|
66
|
+
) locks ON (que_jobs.id=locks.job_id)
|
67
|
+
WHERE locks.job_id IS NULL
|
68
|
+
AND error_count > 0
|
69
|
+
AND (
|
70
|
+
job_class ILIKE ($3)
|
71
|
+
OR que_jobs.args #>> '{0, job_class}' ILIKE ($3)
|
72
|
+
)
|
66
73
|
ORDER BY run_at
|
67
74
|
LIMIT $1::int
|
68
75
|
OFFSET $2::int
|
@@ -74,8 +81,13 @@ Que::Web::SQL = {
|
|
74
81
|
SELECT (classid::bigint << 32) + objid::bigint AS job_id
|
75
82
|
FROM pg_locks
|
76
83
|
WHERE locktype = 'advisory'
|
77
|
-
) locks
|
78
|
-
WHERE locks.job_id IS NULL
|
84
|
+
) locks ON (que_jobs.id=locks.job_id)
|
85
|
+
WHERE locks.job_id IS NULL
|
86
|
+
AND error_count = 0
|
87
|
+
AND (
|
88
|
+
job_class ILIKE ($3)
|
89
|
+
OR que_jobs.args #>> '{0, job_class}' ILIKE ($3)
|
90
|
+
)
|
79
91
|
ORDER BY run_at
|
80
92
|
LIMIT $1::int
|
81
93
|
OFFSET $2::int
|
@@ -86,18 +98,19 @@ Que::Web::SQL = {
|
|
86
98
|
reschedule_job: <<-SQL.freeze,
|
87
99
|
WITH target AS (#{lock_job_sql})
|
88
100
|
UPDATE que_jobs
|
89
|
-
SET run_at = $2::timestamptz
|
101
|
+
SET run_at = $2::timestamptz,
|
102
|
+
expired_at = NULL
|
90
103
|
FROM target
|
91
104
|
WHERE target.locked
|
92
|
-
AND target.
|
93
|
-
RETURNING pg_advisory_unlock(target.
|
105
|
+
AND target.id = que_jobs.id
|
106
|
+
RETURNING pg_advisory_unlock(target.id)
|
94
107
|
SQL
|
95
108
|
reschedule_all_scheduled_jobs: reschedule_all_jobs_query(lock_all_scheduled_jobs_sql),
|
96
109
|
reschedule_all_failing_jobs: reschedule_all_jobs_query(lock_all_failing_jobs_sql),
|
97
110
|
fetch_job: <<-SQL.freeze,
|
98
111
|
SELECT *
|
99
112
|
FROM que_jobs
|
100
|
-
WHERE
|
113
|
+
WHERE id = $1::bigint
|
101
114
|
LIMIT 1
|
102
115
|
SQL
|
103
116
|
}.freeze
|
data/lib/que/web/viewmodels.rb
CHANGED
@@ -1,18 +1,26 @@
|
|
1
1
|
module Que::Web::Viewmodels
|
2
2
|
class Job < Struct.new(
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
:priority, :queue, :run_at)
|
3
|
+
:priority, :run_at, :id, :job_class, :error_count, :last_error_message,
|
4
|
+
:queue, :last_error_backtrace, :finished_at, :expired_at, :args, :data,
|
5
|
+
:backend_pid)
|
7
6
|
|
8
7
|
def initialize(job)
|
9
8
|
members.each do |m|
|
10
|
-
self[m] = job[m
|
9
|
+
self[m] = job[m]
|
11
10
|
end
|
12
11
|
end
|
13
12
|
|
14
13
|
def past_due?(relative_to = Time.now)
|
15
14
|
run_at < relative_to
|
16
15
|
end
|
16
|
+
|
17
|
+
def humanized_job_class
|
18
|
+
case job_class
|
19
|
+
when "ActiveJob::QueueAdapters::QueAdapter::JobWrapper"
|
20
|
+
args.first[:job_class]
|
21
|
+
else
|
22
|
+
job_class
|
23
|
+
end
|
24
|
+
end
|
17
25
|
end
|
18
26
|
end
|