que-web 0.7.2 → 0.9.3
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 +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
|