que-web 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/README.md +41 -3
- data/lib/que/web.rb +31 -10
- data/lib/que/web/sql.rb +56 -54
- data/que-web.gemspec +1 -1
- data/web/public/styles/application.css +4 -0
- data/web/views/_navbar.erb +4 -4
- data/web/views/_search.erb +10 -0
- data/web/views/failing.erb +7 -4
- data/web/views/index.erb +7 -4
- data/web/views/running.erb +4 -1
- data/web/views/scheduled.erb +7 -4
- data/web/views/show.erb +2 -2
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a2be8dc64c1ad88ec87d8850ca883595b6ddd37
|
4
|
+
data.tar.gz: 2d0157762713b670c0d06be83ff0b48976164254
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14476a70a236bc448525729dda19d0c13432daa7e81568b5dcd9a640885370c3f3943277fbeb9facd224d867edf7ecb424687aebf11ed4a7cfab945ff1e8d904
|
7
|
+
data.tar.gz: e8d894075794550693695fcbb288f1ce16669e79b815c38e6b30378b773bb17629e169fc50625dbdea609d38e07d818d495ddcfca4fd902023b0e2b20ef5f517
|
data/README.md
CHANGED
@@ -22,7 +22,9 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
|
25
|
+
#### With `config.ru`
|
26
|
+
|
27
|
+
Add in `config.ru`:
|
26
28
|
|
27
29
|
```ruby
|
28
30
|
require "que/web"
|
@@ -32,14 +34,50 @@ map "/que" do
|
|
32
34
|
end
|
33
35
|
```
|
34
36
|
|
35
|
-
|
37
|
+
### Rails
|
38
|
+
|
39
|
+
In `config/routes.rb`:
|
36
40
|
|
37
41
|
```ruby
|
38
42
|
require "que/web"
|
39
43
|
mount Que::Web => "/que"
|
40
44
|
```
|
41
45
|
|
42
|
-
|
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
|
+
### Authentication
|
59
|
+
|
60
|
+
#### Devise
|
61
|
+
```ruby
|
62
|
+
# config/routes.rb
|
63
|
+
authenticate :user do
|
64
|
+
mount Que::Web, at: 'que'
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
#### Basic HTTP auth
|
69
|
+
|
70
|
+
In `config/initializers/queweb.rb`:
|
71
|
+
```ruby
|
72
|
+
Que::Web.use(Rack::Auth::Basic) do |user, password|
|
73
|
+
[user, password] == [ENV["QUEWEB_USERNAME"], ENV["QUEWEB_PASSWORD"]]
|
74
|
+
end
|
75
|
+
```
|
76
|
+
Then add the two environment variables to your production environment.
|
77
|
+
|
78
|
+
### Docker
|
79
|
+
|
80
|
+
Run:
|
43
81
|
```
|
44
82
|
docker run -e DATABASE_URL=postgres://username:password@hostname/db_name -p 3002:8080 joevandyk/que-web
|
45
83
|
```
|
data/lib/que/web.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "sinatra"
|
1
|
+
require "sinatra/base"
|
2
2
|
require "erubis"
|
3
3
|
|
4
4
|
module Que
|
@@ -14,30 +14,30 @@ module Que
|
|
14
14
|
set :erb, :escape_html => true
|
15
15
|
|
16
16
|
get "/" do
|
17
|
-
stats = Que.execute SQL[:dashboard_stats]
|
17
|
+
stats = Que.execute SQL[:dashboard_stats], [search]
|
18
18
|
@dashboard = Viewmodels::Dashboard.new(stats[0])
|
19
19
|
erb :index
|
20
20
|
end
|
21
21
|
|
22
22
|
get "/running" do
|
23
|
-
worker_states = Que.worker_states
|
23
|
+
worker_states = search_running Que.worker_states
|
24
24
|
pager = get_pager worker_states.count
|
25
25
|
@list = Viewmodels::JobList.new(worker_states, pager)
|
26
26
|
erb :running
|
27
27
|
end
|
28
28
|
|
29
29
|
get "/failing" do
|
30
|
-
stats = Que.execute SQL[:dashboard_stats]
|
30
|
+
stats = Que.execute SQL[:dashboard_stats], [search]
|
31
31
|
pager = get_pager stats[0]["failing"]
|
32
|
-
failing_jobs = Que.execute SQL[:failing_jobs], [pager.page_size, pager.offset]
|
32
|
+
failing_jobs = Que.execute SQL[:failing_jobs], [pager.page_size, pager.offset, search]
|
33
33
|
@list = Viewmodels::JobList.new(failing_jobs, pager)
|
34
34
|
erb :failing
|
35
35
|
end
|
36
36
|
|
37
37
|
get "/scheduled" do
|
38
|
-
stats = Que.execute SQL[:dashboard_stats]
|
38
|
+
stats = Que.execute SQL[:dashboard_stats], [search]
|
39
39
|
pager = get_pager stats[0]["scheduled"]
|
40
|
-
scheduled_jobs = Que.execute SQL[:scheduled_jobs], [pager.page_size, pager.offset]
|
40
|
+
scheduled_jobs = Que.execute SQL[:scheduled_jobs], [pager.page_size, pager.offset, search]
|
41
41
|
|
42
42
|
@list = Viewmodels::JobList.new(scheduled_jobs, pager)
|
43
43
|
erb :scheduled
|
@@ -85,6 +85,21 @@ module Que
|
|
85
85
|
Pager.new(page, PAGE_SIZE, record_count)
|
86
86
|
end
|
87
87
|
|
88
|
+
def search
|
89
|
+
return '%' unless search_param.present?
|
90
|
+
"%#{search_param}%"
|
91
|
+
end
|
92
|
+
|
93
|
+
def search_running(jobs)
|
94
|
+
return jobs unless search_param.present?
|
95
|
+
jobs.select { |job| job.job_class.include? search_param }
|
96
|
+
end
|
97
|
+
|
98
|
+
def search_param
|
99
|
+
return unless params['search'].present?
|
100
|
+
params['search'].gsub(/[^0-9A-Za-z:]/, '')
|
101
|
+
end
|
102
|
+
|
88
103
|
after { session[FLASH_KEY] = {} if @sweep_flash }
|
89
104
|
|
90
105
|
helpers do
|
@@ -92,6 +107,15 @@ module Que
|
|
92
107
|
"#{env['SCRIPT_NAME']}/"
|
93
108
|
end
|
94
109
|
|
110
|
+
def link_to(path)
|
111
|
+
to path_with_search(path)
|
112
|
+
end
|
113
|
+
|
114
|
+
def path_with_search(path)
|
115
|
+
path += "?search=#{search_param}" if search_param.present?
|
116
|
+
path
|
117
|
+
end
|
118
|
+
|
95
119
|
def active_class(pattern)
|
96
120
|
if request.path.match pattern
|
97
121
|
"active"
|
@@ -109,9 +133,6 @@ module Que
|
|
109
133
|
end
|
110
134
|
|
111
135
|
def relative_time(time)
|
112
|
-
if time.is_a?(String)
|
113
|
-
time = Time.parse(time)
|
114
|
-
end
|
115
136
|
%{<time class="timeago" datetime="#{time.utc.iso8601}">#{time.utc}</time>}
|
116
137
|
end
|
117
138
|
|
data/lib/que/web/sql.rb
CHANGED
@@ -1,56 +1,58 @@
|
|
1
1
|
Que::Web::SQL = {
|
2
|
-
:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
WHERE
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
WHERE
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
2
|
+
dashboard_stats: <<-SQL.freeze,
|
3
|
+
SELECT count(*) AS total,
|
4
|
+
count(locks.job_id) AS running,
|
5
|
+
coalesce(sum((error_count > 0 AND locks.job_id IS NULL)::int), 0) AS failing,
|
6
|
+
coalesce(sum((error_count = 0 AND locks.job_id IS NULL)::int), 0) AS scheduled
|
7
|
+
FROM que_jobs
|
8
|
+
LEFT JOIN (
|
9
|
+
SELECT (classid::bigint << 32) + objid::bigint AS job_id
|
10
|
+
FROM pg_locks
|
11
|
+
WHERE locktype = 'advisory'
|
12
|
+
) locks USING (job_id)
|
13
|
+
WHERE
|
14
|
+
job_class LIKE ($1)
|
15
|
+
SQL
|
16
|
+
failing_jobs: <<-SQL.freeze,
|
17
|
+
SELECT que_jobs.*
|
18
|
+
FROM que_jobs
|
19
|
+
LEFT JOIN (
|
20
|
+
SELECT (classid::bigint << 32) + objid::bigint AS job_id
|
21
|
+
FROM pg_locks
|
22
|
+
WHERE locktype = 'advisory'
|
23
|
+
) locks USING (job_id)
|
24
|
+
WHERE locks.job_id IS NULL AND error_count > 0 AND job_class LIKE ($3)
|
25
|
+
ORDER BY run_at
|
26
|
+
LIMIT $1::int
|
27
|
+
OFFSET $2::int
|
28
|
+
SQL
|
29
|
+
scheduled_jobs: <<-SQL.freeze,
|
30
|
+
SELECT que_jobs.*
|
31
|
+
FROM que_jobs
|
32
|
+
LEFT JOIN (
|
33
|
+
SELECT (classid::bigint << 32) + objid::bigint AS job_id
|
34
|
+
FROM pg_locks
|
35
|
+
WHERE locktype = 'advisory'
|
36
|
+
) locks USING (job_id)
|
37
|
+
WHERE locks.job_id IS NULL AND error_count = 0 AND job_class LIKE ($3)
|
38
|
+
ORDER BY run_at
|
39
|
+
LIMIT $1::int
|
40
|
+
OFFSET $2::int
|
41
|
+
SQL
|
42
|
+
delete_job: <<-SQL.freeze,
|
43
|
+
DELETE
|
44
|
+
FROM que_jobs
|
45
|
+
WHERE job_id = $1::bigint
|
46
|
+
SQL
|
47
|
+
reschedule_job: <<-SQL.freeze,
|
48
|
+
UPDATE que_jobs
|
49
|
+
SET run_at = $2::timestamptz
|
50
|
+
WHERE job_id = $1::bigint
|
51
|
+
SQL
|
52
|
+
fetch_job: <<-SQL.freeze,
|
53
|
+
SELECT *
|
54
|
+
FROM que_jobs
|
55
|
+
WHERE job_id = $1::bigint
|
56
|
+
LIMIT 1
|
57
|
+
SQL
|
56
58
|
}.freeze
|
data/que-web.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "que-web"
|
7
|
-
spec.version = "0.
|
7
|
+
spec.version = "0.5.0"
|
8
8
|
spec.authors = ["Jason Staten"]
|
9
9
|
spec.email = ["jstaten07@gmail.com"]
|
10
10
|
spec.summary = %q{A web interface for the que queue}
|
data/web/views/_navbar.erb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
<nav class="top-bar" data-topbar role="navigation">
|
2
2
|
<ul class="title-area">
|
3
3
|
<li class="name">
|
4
|
-
<h1><a href="<%= root_path %>">Que</a></h1>
|
4
|
+
<h1><a href="<%= path_with_search root_path %>">Que</a></h1>
|
5
5
|
</li>
|
6
6
|
</ul>
|
7
7
|
<section class="top-bar-section">
|
8
8
|
<ul class="left">
|
9
|
-
<li class="<%= active_class('running') %>"><a href="<%=
|
10
|
-
<li class="<%= active_class('scheduled') %>"><a href="<%=
|
11
|
-
<li class="<%= active_class('failing') %>"><a href="<%=
|
9
|
+
<li class="<%= active_class('running') %>"><a href="<%= link_to 'running' %>"><span>Running</span></a></li>
|
10
|
+
<li class="<%= active_class('scheduled') %>"><a href="<%= link_to 'scheduled' %>"><span>Scheduled</span></a></li>
|
11
|
+
<li class="<%= active_class('failing') %>"><a href="<%= link_to 'failing' %>"><span>Failing</span></a></li>
|
12
12
|
</ul>
|
13
13
|
<ul class="right version">
|
14
14
|
<li>Que <%= Que::Version %></li>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<form class="search" action="<%= request.path %>" method="get">
|
2
|
+
<div class="row collapse">
|
3
|
+
<div class="small-8 columns">
|
4
|
+
<input type="text" name="search" value="<%= search_param %>" />
|
5
|
+
</div>
|
6
|
+
<div class="small-4 columns">
|
7
|
+
<button class="button postfix">Search</button>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
</form>
|
data/web/views/failing.erb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
<div class="row">
|
2
|
-
<div class="small-12 columns">
|
2
|
+
<div class="small-12 medium-8 columns">
|
3
3
|
<h1><%= @list.total %> Failing Job<%= @list.total == 1 ? "" : "s" %></h1>
|
4
4
|
</div>
|
5
|
+
<div class="small-12 medium-4 columns">
|
6
|
+
<%== erb :_search %>
|
7
|
+
</div>
|
5
8
|
</div>
|
6
9
|
<div class="row">
|
7
10
|
<div class="small-12 columns">
|
@@ -21,7 +24,7 @@
|
|
21
24
|
<tbody>
|
22
25
|
<% @list.page_jobs.each do |job| %>
|
23
26
|
<tr>
|
24
|
-
<td><a href="<%=
|
27
|
+
<td><a href="<%= link_to "jobs/#{job.job_id}" %>">
|
25
28
|
<%== relative_time job.run_at %></a>
|
26
29
|
<%== erb :_past_due, locals: {job: job} %>
|
27
30
|
</td>
|
@@ -31,13 +34,13 @@
|
|
31
34
|
<td><pre><%= format_args job %></pre></td>
|
32
35
|
<td><%= format_error job %></pre></td>
|
33
36
|
<td>
|
34
|
-
<form action="<%=
|
37
|
+
<form action="<%= link_to "jobs/#{job.job_id}" %>" method="post">
|
35
38
|
<input type="hidden" name="_method" value="put" />
|
36
39
|
<button class="plain" title="Retry Immediately"><i class="fa fa-refresh"></i></button>
|
37
40
|
</form>
|
38
41
|
</td>
|
39
42
|
<td>
|
40
|
-
<form action="<%=
|
43
|
+
<form action="<%= link_to "jobs/#{job.job_id}" %>" method="post">
|
41
44
|
<input type="hidden" name="_method" value="delete" />
|
42
45
|
<button class="plain" title="Delete"><i class="fa fa-trash"></i></button>
|
43
46
|
</form>
|
data/web/views/index.erb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
<div class="row">
|
2
|
-
<div class="small-12 columns">
|
2
|
+
<div class="small-12 medium-8 columns">
|
3
3
|
<h1>Jobs</h1>
|
4
4
|
</div>
|
5
|
+
<div class="small-12 medium-4 columns">
|
6
|
+
<%== erb :_search %>
|
7
|
+
</div>
|
5
8
|
</div>
|
6
9
|
<div class="row">
|
7
|
-
<a class="small-12 large-4 columns" href="<%=
|
10
|
+
<a class="small-12 large-4 columns" href="<%= link_to 'running' %>">
|
8
11
|
<div class="dashboard-stat running">
|
9
12
|
<div class="cell">
|
10
13
|
<h2>Running<h2>
|
@@ -14,7 +17,7 @@
|
|
14
17
|
</div>
|
15
18
|
</div>
|
16
19
|
</a>
|
17
|
-
<a class="small-12 large-4 columns" href="<%=
|
20
|
+
<a class="small-12 large-4 columns" href="<%= link_to 'scheduled' %>">
|
18
21
|
<div class="dashboard-stat scheduled">
|
19
22
|
<div class="cell">
|
20
23
|
<h2>Scheduled<h2>
|
@@ -24,7 +27,7 @@
|
|
24
27
|
</div>
|
25
28
|
</div>
|
26
29
|
</a>
|
27
|
-
<a class="small-12 large-4 columns" href="<%=
|
30
|
+
<a class="small-12 large-4 columns" href="<%= link_to 'failing' %>">
|
28
31
|
<div class="dashboard-stat failing">
|
29
32
|
<div class="cell">
|
30
33
|
<h2>Failing<h2>
|
data/web/views/running.erb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
<div class="row">
|
2
|
-
<div class="small-12 columns">
|
2
|
+
<div class="small-12 medium-8 columns">
|
3
3
|
<h1><%= @list.total %> Running Job<%= @list.total == 1 ? "" : "s" %></h1>
|
4
4
|
</div>
|
5
|
+
<div class="small-12 medium-4 columns">
|
6
|
+
<%== erb :_search %>
|
7
|
+
</div>
|
5
8
|
</div>
|
6
9
|
<div class="row">
|
7
10
|
<div class="small-12 columns">
|
data/web/views/scheduled.erb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
<div class="row">
|
2
|
-
<div class="small-12 columns">
|
2
|
+
<div class="small-12 medium-8 columns">
|
3
3
|
<h1><%= @list.total %> Scheduled Job<%= @list.total == 1 ? "" : "s" %></h1>
|
4
4
|
</div>
|
5
|
+
<div class="small-12 medium-4 columns">
|
6
|
+
<%== erb :_search %>
|
7
|
+
</div>
|
5
8
|
</div>
|
6
9
|
<div class="row">
|
7
10
|
<div class="small-12 columns">
|
@@ -20,20 +23,20 @@
|
|
20
23
|
<% @list.page_jobs.each do |job| %>
|
21
24
|
<tr>
|
22
25
|
<td>
|
23
|
-
<a href="<%=
|
26
|
+
<a href="<%= link_to "jobs/#{job.job_id}" %>"><%== relative_time job.run_at %></a>
|
24
27
|
<%== erb :_past_due, locals: {job: job}%>
|
25
28
|
</td>
|
26
29
|
<td><%= job.job_class %></td>
|
27
30
|
<td><%= job.queue %></td>
|
28
31
|
<td><pre><%= format_args job %></pre></td>
|
29
32
|
<td>
|
30
|
-
<form action="<%=
|
33
|
+
<form action="<%= link_to "jobs/#{job.job_id}" %>" method="post">
|
31
34
|
<input type="hidden" name="_method" value="put" />
|
32
35
|
<button class="plain" title="Run Immediately"><i class="fa fa-play-circle"></i></button>
|
33
36
|
</form>
|
34
37
|
</td>
|
35
38
|
<td>
|
36
|
-
<form action="<%=
|
39
|
+
<form action="<%= link_to "jobs/#{job.job_id}" %>" method="post">
|
37
40
|
<input type="hidden" name="_method" value="delete" />
|
38
41
|
<button class="plain" title="Delete"><i class="fa fa-trash"></i></button>
|
39
42
|
</form>
|
data/web/views/show.erb
CHANGED
@@ -44,11 +44,11 @@
|
|
44
44
|
</div>
|
45
45
|
<div class="row">
|
46
46
|
<div class="small-12 columns">
|
47
|
-
<form class="form-inline" action="<%=
|
47
|
+
<form class="form-inline" action="<%= link_to "/jobs/#{@job.job_id}" %>" method="post">
|
48
48
|
<input type="hidden" name="_method" value="put" />
|
49
49
|
<button><i class="fa fa-play-circle"></i> Run Immediately</button>
|
50
50
|
</form>
|
51
|
-
<form class="form-inline" maction="<%=
|
51
|
+
<form class="form-inline" maction="<%= link_to "/jobs/#{@job.job_id}" %>" method="post">
|
52
52
|
<input type="hidden" name="_method" value="Delete" />
|
53
53
|
<button class="button alert"><i class="fa fa-trash"></i> Delete</button>
|
54
54
|
</form>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: que-web
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Staten
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: que
|
@@ -150,6 +150,7 @@ files:
|
|
150
150
|
- web/views/_navbar.erb
|
151
151
|
- web/views/_pager.erb
|
152
152
|
- web/views/_past_due.erb
|
153
|
+
- web/views/_search.erb
|
153
154
|
- web/views/failing.erb
|
154
155
|
- web/views/index.erb
|
155
156
|
- web/views/layout.erb
|
@@ -176,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
176
177
|
version: '0'
|
177
178
|
requirements: []
|
178
179
|
rubyforge_project:
|
179
|
-
rubygems_version: 2.
|
180
|
+
rubygems_version: 2.6.11
|
180
181
|
signing_key:
|
181
182
|
specification_version: 4
|
182
183
|
summary: A web interface for the que queue
|