que-web 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|