good_job 1.3.3 → 1.4.1
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/CHANGELOG.md +78 -8
- data/README.md +9 -0
- data/engine/app/{views/assets/_style.css.erb → assets/style.css} +0 -0
- data/engine/app/{views/vendor/bootstrap/_bootstrap-native.js.erb → assets/vendor/bootstrap/bootstrap-native.js} +0 -0
- data/engine/app/{views/vendor/bootstrap/_bootstrap.css.erb → assets/vendor/bootstrap/bootstrap.css} +0 -0
- data/engine/app/{views/vendor/chartist/_chartist.css.erb → assets/vendor/chartist/chartist.css} +0 -0
- data/engine/app/{views/vendor/chartist/_chartist.js.erb → assets/vendor/chartist/chartist.js} +0 -0
- data/engine/app/controllers/good_job/active_jobs_controller.rb +1 -1
- data/engine/app/controllers/good_job/dashboards_controller.rb +2 -2
- data/engine/app/views/good_job/dashboards/index.html.erb +19 -7
- data/engine/app/views/layouts/good_job/base.html.erb +6 -6
- data/engine/app/views/shared/_chart.erb +1 -1
- data/engine/app/views/shared/_jobs_table.erb +27 -25
- data/lib/good_job.rb +7 -8
- data/lib/good_job/configuration.rb +4 -3
- data/lib/good_job/job.rb +7 -1
- data/lib/good_job/lockable.rb +56 -11
- data/lib/good_job/log_subscriber.rb +7 -7
- data/lib/good_job/notifier.rb +26 -14
- data/lib/good_job/poller.rb +3 -0
- data/lib/good_job/scheduler.rb +8 -5
- data/lib/good_job/version.rb +1 -1
- metadata +8 -134
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac71f85784bd491d995252ed498d55642ee511a402ad093cc056fd2e062a437b
|
4
|
+
data.tar.gz: 33f1a9ebf6952f3140046338bb616a4a81c469b4099f526e56d15b9aa1f8951d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1660dd44eca81ce42cbdb917253dfb340d5e5a4b371275f51eb919fc5aacb3485c6bbd87164d49d07547682efe311fb1a41bce35599ab5d45b8bd669d1e840c2
|
7
|
+
data.tar.gz: 1c2994d95046ea9f692539dffcb0bfa33d81daed73886a2fef7ab9c9c6063b4085c17f8cc7ed93bcfab999ca25ffef1db31fa82344e3a31a6dcbdc3a84c966ed
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,83 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v1.4.1](https://github.com/bensheldon/good_job/tree/v1.4.1) (2021-01-09)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.4.0...v1.4.1)
|
6
|
+
|
7
|
+
**Fixed bugs:**
|
8
|
+
|
9
|
+
- Do not add lib/generators to Zeitwerk autoloader [\#192](https://github.com/bensheldon/good_job/pull/192) ([bensheldon](https://github.com/bensheldon))
|
10
|
+
|
11
|
+
**Closed issues:**
|
12
|
+
|
13
|
+
- Issues with Heroku and Good Job [\#184](https://github.com/bensheldon/good_job/issues/184)
|
14
|
+
|
15
|
+
**Merged pull requests:**
|
16
|
+
|
17
|
+
- Add missing YARD docs and Dashboard screenshot [\#191](https://github.com/bensheldon/good_job/pull/191) ([bensheldon](https://github.com/bensheldon))
|
18
|
+
|
19
|
+
## [v1.4.0](https://github.com/bensheldon/good_job/tree/v1.4.0) (2020-12-31)
|
20
|
+
|
21
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.6...v1.4.0)
|
22
|
+
|
23
|
+
**Implemented enhancements:**
|
24
|
+
|
25
|
+
- Add JRuby support [\#167](https://github.com/bensheldon/good_job/pull/167) ([bensheldon](https://github.com/bensheldon))
|
26
|
+
|
27
|
+
## [v1.3.6](https://github.com/bensheldon/good_job/tree/v1.3.6) (2020-12-30)
|
28
|
+
|
29
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.5...v1.3.6)
|
30
|
+
|
31
|
+
**Implemented enhancements:**
|
32
|
+
|
33
|
+
- Call GoodJob.on\_thread\_error when Notifier thread raises exception [\#185](https://github.com/bensheldon/good_job/pull/185) ([bensheldon](https://github.com/bensheldon))
|
34
|
+
- Improve dashboard UI, fix button state, add unfiltering [\#181](https://github.com/bensheldon/good_job/pull/181) ([bensheldon](https://github.com/bensheldon))
|
35
|
+
|
36
|
+
**Fixed bugs:**
|
37
|
+
|
38
|
+
- Replace ActiveRecord execute usage and avoid potential memory leakage [\#187](https://github.com/bensheldon/good_job/issues/187)
|
39
|
+
- Does good\_job hold on to advisory locks for finished jobs? [\#177](https://github.com/bensheldon/good_job/issues/177)
|
40
|
+
|
41
|
+
**Merged pull requests:**
|
42
|
+
|
43
|
+
- Run tests with Rails default configuration to enable Zeitwerk [\#190](https://github.com/bensheldon/good_job/pull/190) ([bensheldon](https://github.com/bensheldon))
|
44
|
+
- Update all Lockable queries to use exec\_query instead of execute; clear async\_exec results [\#189](https://github.com/bensheldon/good_job/pull/189) ([bensheldon](https://github.com/bensheldon))
|
45
|
+
- Have Lockable\#advisory\_locked? directly query pg\_locks table [\#188](https://github.com/bensheldon/good_job/pull/188) ([bensheldon](https://github.com/bensheldon))
|
46
|
+
- Update development gems, including Rails v6.1 and Rails HEAD [\#186](https://github.com/bensheldon/good_job/pull/186) ([bensheldon](https://github.com/bensheldon))
|
47
|
+
- Update Appraisals for Rails 6.1 [\#183](https://github.com/bensheldon/good_job/pull/183) ([bensheldon](https://github.com/bensheldon))
|
48
|
+
- Add Ruby 3 to CI test matrix [\#182](https://github.com/bensheldon/good_job/pull/182) ([bensheldon](https://github.com/bensheldon))
|
49
|
+
|
50
|
+
## [v1.3.5](https://github.com/bensheldon/good_job/tree/v1.3.5) (2020-12-17)
|
51
|
+
|
52
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.4...v1.3.5)
|
53
|
+
|
54
|
+
**Fixed bugs:**
|
55
|
+
|
56
|
+
- Ensure advisory lock CTE is MATERIALIZED on Postgres v12+ [\#179](https://github.com/bensheldon/good_job/pull/179) ([bensheldon](https://github.com/bensheldon))
|
57
|
+
- Ensure that deleted jobs are unlocked [\#178](https://github.com/bensheldon/good_job/pull/178) ([bensheldon](https://github.com/bensheldon))
|
58
|
+
|
59
|
+
**Closed issues:**
|
60
|
+
|
61
|
+
- not running jobs [\#168](https://github.com/bensheldon/good_job/issues/168)
|
62
|
+
- how to run good\_job on a separate machine [\#162](https://github.com/bensheldon/good_job/issues/162)
|
63
|
+
|
64
|
+
**Merged pull requests:**
|
65
|
+
|
66
|
+
- Add Appraisal for Rails 6.1-rc2 [\#175](https://github.com/bensheldon/good_job/pull/175) ([bensheldon](https://github.com/bensheldon))
|
67
|
+
|
68
|
+
## [v1.3.4](https://github.com/bensheldon/good_job/tree/v1.3.4) (2020-12-02)
|
69
|
+
|
70
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.3...v1.3.4)
|
71
|
+
|
72
|
+
**Fixed bugs:**
|
73
|
+
|
74
|
+
- Fix job ordering for Rails 6.1 [\#174](https://github.com/bensheldon/good_job/pull/174) ([morgoth](https://github.com/morgoth))
|
75
|
+
|
3
76
|
## [v1.3.3](https://github.com/bensheldon/good_job/tree/v1.3.3) (2020-12-01)
|
4
77
|
|
5
78
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.2...v1.3.3)
|
6
79
|
|
7
|
-
**
|
80
|
+
**Implemented enhancements:**
|
8
81
|
|
9
82
|
- UI: Admin UI with filters and space efficient layout [\#173](https://github.com/bensheldon/good_job/pull/173) ([zealot128](https://github.com/zealot128))
|
10
83
|
|
@@ -51,9 +124,6 @@
|
|
51
124
|
**Implemented enhancements:**
|
52
125
|
|
53
126
|
- Lengthen default poll interval from 1 to 5 seconds [\#156](https://github.com/bensheldon/good_job/pull/156) ([bensheldon](https://github.com/bensheldon))
|
54
|
-
|
55
|
-
**Merged pull requests:**
|
56
|
-
|
57
127
|
- Rename reperform\_jobs\_on\_standard\_error to retry\_on\_unhandled\_error [\#154](https://github.com/bensheldon/good_job/pull/154) ([morgoth](https://github.com/morgoth))
|
58
128
|
|
59
129
|
## [v1.2.6](https://github.com/bensheldon/good_job/tree/v1.2.6) (2020-09-29)
|
@@ -155,7 +225,6 @@
|
|
155
225
|
**Merged pull requests:**
|
156
226
|
|
157
227
|
- stop depending on all rails libs [\#104](https://github.com/bensheldon/good_job/pull/104) ([thilo](https://github.com/thilo))
|
158
|
-
- Use more ActiveRecord in Lockable and not connection.execute [\#102](https://github.com/bensheldon/good_job/pull/102) ([bensheldon](https://github.com/bensheldon))
|
159
228
|
|
160
229
|
## [v1.2.2](https://github.com/bensheldon/good_job/tree/v1.2.2) (2020-08-27)
|
161
230
|
|
@@ -164,11 +233,13 @@
|
|
164
233
|
**Implemented enhancements:**
|
165
234
|
|
166
235
|
- Run Github Action tests against Ruby 2.5, 2.6, 2.7 [\#100](https://github.com/bensheldon/good_job/issues/100)
|
236
|
+
- Name the thread pools [\#96](https://github.com/bensheldon/good_job/pull/96) ([sj26](https://github.com/sj26))
|
167
237
|
|
168
238
|
**Fixed bugs:**
|
169
239
|
|
170
240
|
- Freezes puma on code change [\#95](https://github.com/bensheldon/good_job/issues/95)
|
171
241
|
- Ruby 2.7 keyword arguments warning [\#93](https://github.com/bensheldon/good_job/issues/93)
|
242
|
+
- Return to using executor.wrap around Scheduler execution task [\#99](https://github.com/bensheldon/good_job/pull/99) ([bensheldon](https://github.com/bensheldon))
|
172
243
|
|
173
244
|
**Closed issues:**
|
174
245
|
|
@@ -176,11 +247,10 @@
|
|
176
247
|
|
177
248
|
**Merged pull requests:**
|
178
249
|
|
250
|
+
- Use more ActiveRecord in Lockable and not connection.execute [\#102](https://github.com/bensheldon/good_job/pull/102) ([bensheldon](https://github.com/bensheldon))
|
179
251
|
- Run CI tests on Ruby 2.5, 2.6, and 2.7 [\#101](https://github.com/bensheldon/good_job/pull/101) ([arku](https://github.com/arku))
|
180
|
-
- Return to using executor.wrap around Scheduler execution task [\#99](https://github.com/bensheldon/good_job/pull/99) ([bensheldon](https://github.com/bensheldon))
|
181
252
|
- Fix Ruby 2.7 keyword arguments warning [\#98](https://github.com/bensheldon/good_job/pull/98) ([arku](https://github.com/arku))
|
182
253
|
- Remove executor/reloader for less interlocking [\#97](https://github.com/bensheldon/good_job/pull/97) ([sj26](https://github.com/sj26))
|
183
|
-
- Name the thread pools [\#96](https://github.com/bensheldon/good_job/pull/96) ([sj26](https://github.com/sj26))
|
184
254
|
- Add test for `rails g good\_job:install` [\#94](https://github.com/bensheldon/good_job/pull/94) ([arku](https://github.com/arku))
|
185
255
|
|
186
256
|
## [v1.2.1](https://github.com/bensheldon/good_job/tree/v1.2.1) (2020-08-21)
|
@@ -438,6 +508,7 @@
|
|
438
508
|
- Add pg gem as explicit dependency [\#13](https://github.com/bensheldon/good_job/pull/13) ([bensheldon](https://github.com/bensheldon))
|
439
509
|
- Bump nokogiri from 1.10.7 to 1.10.9 [\#12](https://github.com/bensheldon/good_job/pull/12) ([dependabot[bot]](https://github.com/apps/dependabot))
|
440
510
|
- Add Appraisal with tests for Rails 5.1, 5.2, 6.0 [\#11](https://github.com/bensheldon/good_job/pull/11) ([bensheldon](https://github.com/bensheldon))
|
511
|
+
- Use Rails.logger and ActiveSupport::Notifications for logging instead of puts [\#10](https://github.com/bensheldon/good_job/pull/10) ([bensheldon](https://github.com/bensheldon))
|
441
512
|
|
442
513
|
## [v0.2.0](https://github.com/bensheldon/good_job/tree/v0.2.0) (2020-03-06)
|
443
514
|
|
@@ -445,7 +516,6 @@
|
|
445
516
|
|
446
517
|
**Merged pull requests:**
|
447
518
|
|
448
|
-
- Use Rails.logger and ActiveSupport::Notifications for logging instead of puts [\#10](https://github.com/bensheldon/good_job/pull/10) ([bensheldon](https://github.com/bensheldon))
|
449
519
|
- Remove minitest files [\#9](https://github.com/bensheldon/good_job/pull/9) ([bensheldon](https://github.com/bensheldon))
|
450
520
|
- Use scheduled\_at and priority for scheduling [\#8](https://github.com/bensheldon/good_job/pull/8) ([bensheldon](https://github.com/bensheldon))
|
451
521
|
- Create Github Action workflow for PRs and Issues [\#7](https://github.com/bensheldon/good_job/pull/7) ([bensheldon](https://github.com/bensheldon))
|
data/README.md
CHANGED
@@ -30,6 +30,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
30
30
|
## Table of contents
|
31
31
|
|
32
32
|
- [Set up](#set-up)
|
33
|
+
- [Compatibility](#compatibility)
|
33
34
|
- [Configuration](#configuration)
|
34
35
|
- [Command-line options](#command-line-options)
|
35
36
|
- [`good_job start`](#good_job-start)
|
@@ -123,6 +124,12 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
123
124
|
|
124
125
|
Additional configuration is likely necessary, see the reference below for async configuration.
|
125
126
|
|
127
|
+
## Compatibility
|
128
|
+
|
129
|
+
- **Ruby on Rails:** 5.2+
|
130
|
+
- **Ruby:** MRI 2.5+. JRuby 9.13+ (_JRuby's `activerecord-jdbcpostgresql-adapter` gem does not support Postgres LISTEN/NOTIFY)._
|
131
|
+
- **Postgres:** 9.6+
|
132
|
+
|
126
133
|
## Configuration
|
127
134
|
|
128
135
|
### Command-line options
|
@@ -227,6 +234,8 @@ GoodJob.on_thread_error = -> (exception) { Raven.capture_exception(exception) }
|
|
227
234
|
|
228
235
|
### Dashboard
|
229
236
|
|
237
|
+

|
238
|
+
|
230
239
|
_🚧 GoodJob's dashboard is a work in progress. Please contribute ideas and code on [Github](https://github.com/bensheldon/good_job/issues)._
|
231
240
|
|
232
241
|
GoodJob includes a Dashboard as a mountable `Rails::Engine`.
|
File without changes
|
File without changes
|
data/engine/app/{views/vendor/bootstrap/_bootstrap.css.erb → assets/vendor/bootstrap/bootstrap.css}
RENAMED
File without changes
|
data/engine/app/{views/vendor/chartist/_chartist.css.erb → assets/vendor/chartist/chartist.css}
RENAMED
File without changes
|
data/engine/app/{views/vendor/chartist/_chartist.js.erb → assets/vendor/chartist/chartist.js}
RENAMED
File without changes
|
@@ -2,7 +2,7 @@ module GoodJob
|
|
2
2
|
class ActiveJobsController < GoodJob::BaseController
|
3
3
|
def show
|
4
4
|
@jobs = GoodJob::Job.where("serialized_params ->> 'job_id' = ?", params[:id])
|
5
|
-
.order(
|
5
|
+
.order(Arel.sql("COALESCE(scheduled_at, created_at) DESC"))
|
6
6
|
end
|
7
7
|
end
|
8
8
|
end
|
@@ -42,11 +42,11 @@ module GoodJob
|
|
42
42
|
GoodJob::Job.group("serialized_params->>'job_class'").count
|
43
43
|
end
|
44
44
|
|
45
|
-
def
|
45
|
+
def to_params(override)
|
46
46
|
{
|
47
47
|
state: params[:state],
|
48
48
|
job_class: params[:job_class],
|
49
|
-
}.merge(override).delete_if { |_, v| v.nil? }
|
49
|
+
}.merge(override).delete_if { |_, v| v.nil? }
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -8,18 +8,30 @@
|
|
8
8
|
<small>Filter by job class</small>
|
9
9
|
<br>
|
10
10
|
<% @filter.job_classes.each do |name, count| %>
|
11
|
-
|
12
|
-
<%=
|
13
|
-
|
11
|
+
<% if params[:job_class] == name %>
|
12
|
+
<%= link_to(root_path(@filter.to_params(job_class: nil)), class: 'btn btn-sm btn-outline-secondary active', role: "button", "aria-pressed": true) do %>
|
13
|
+
<%= name %> (<%= count %>)
|
14
|
+
<% end %>
|
15
|
+
<% else %>
|
16
|
+
<%= link_to(root_path(@filter.to_params(job_class: name)), class: 'btn btn-sm btn-outline-secondary', role: "button") do %>
|
17
|
+
<%= name %> (<%= count %>)
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
14
20
|
<% end %>
|
15
21
|
</div>
|
16
22
|
<div>
|
17
23
|
<small>Filter by state</small>
|
18
24
|
<br>
|
19
25
|
<% @filter.states.each do |name, count| %>
|
20
|
-
|
21
|
-
<%=
|
22
|
-
|
26
|
+
<% if params[:state] == name %>
|
27
|
+
<%= link_to(root_path(@filter.to_params(state: nil)), class: 'btn btn-sm btn-outline-secondary active', role: "button", "aria-pressed": true) do %>
|
28
|
+
<%= name %> (<%= count %>)
|
29
|
+
<% end %>
|
30
|
+
<% else %>
|
31
|
+
<%= link_to(root_path(@filter.to_params(state: name)), class: 'btn btn-sm btn-outline-secondary', role: "button") do %>
|
32
|
+
<%= name %> (<%= count %>)
|
33
|
+
<% end %>
|
34
|
+
<% end %>
|
23
35
|
<% end %>
|
24
36
|
</div>
|
25
37
|
</div>
|
@@ -28,7 +40,7 @@
|
|
28
40
|
<% if @filter.jobs.present? %>
|
29
41
|
<%= render 'shared/jobs_table', jobs: @filter.jobs %>
|
30
42
|
|
31
|
-
<nav aria-label="Job pagination">
|
43
|
+
<nav aria-label="Job pagination" class="mt-3">
|
32
44
|
<ul class="pagination">
|
33
45
|
<li class="page-item">
|
34
46
|
<%= link_to({ after_scheduled_at: (@filter.last.scheduled_at || @filter.last.created_at), after_id: @filter.last.id }, class: "page-link") do %>
|
@@ -1,19 +1,19 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
3
|
<head>
|
4
|
-
<title>Good
|
4
|
+
<title>Good Job Dashboard</title>
|
5
5
|
<%= csrf_meta_tags %>
|
6
6
|
<%= csp_meta_tag %>
|
7
7
|
|
8
8
|
<style>
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
<%== render file: GoodJob::Engine.root.join("app", "assets", "vendor", "bootstrap", "bootstrap.css") %>
|
10
|
+
<%== render file: GoodJob::Engine.root.join("app", "assets", "vendor", "chartist", "chartist.css") %>
|
11
|
+
<%== render file: GoodJob::Engine.root.join("app", "assets", "style.css") %>
|
12
12
|
</style>
|
13
13
|
|
14
14
|
<script>
|
15
|
-
|
16
|
-
|
15
|
+
<%== render file: GoodJob::Engine.root.join("app", "assets", "vendor", "bootstrap", "bootstrap-native.js") %>
|
16
|
+
<%== render file: GoodJob::Engine.root.join("app", "assets", "vendor", "chartist", "chartist.js") %>
|
17
17
|
</script>
|
18
18
|
</head>
|
19
19
|
<body>
|
@@ -1,26 +1,28 @@
|
|
1
|
-
<div class="
|
2
|
-
<
|
3
|
-
<
|
4
|
-
<
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
<
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
1
|
+
<div class="card my-3">
|
2
|
+
<div class="table-responsive">
|
3
|
+
<table class="table card-table table-bordered table-hover table-sm mb-0">
|
4
|
+
<thead>
|
5
|
+
<th>GoodJob ID</th>
|
6
|
+
<th>ActiveJob ID</th>
|
7
|
+
<th>Job Class</th>
|
8
|
+
<th>Queue</th>
|
9
|
+
<th>Scheduled At</th>
|
10
|
+
<th>Error</th>
|
11
|
+
<th>ActiveJob Params</th>
|
12
|
+
</thead>
|
13
|
+
<tbody>
|
14
|
+
<% jobs.each do |job| %>
|
15
|
+
<tr id="<%= dom_id(job) %>">
|
16
|
+
<td><%= link_to job.id, active_job_path(job.serialized_params['job_id'], anchor: dom_id(job)) %></td>
|
17
|
+
<td><%= link_to job.serialized_params['job_id'], active_job_path(job.serialized_params['job_id']) %></td>
|
18
|
+
<td><%= job.serialized_params['job_class'] %></td>
|
19
|
+
<td><%= job.queue_name %></td>
|
20
|
+
<td><%= job.scheduled_at || job.created_at %></td>
|
21
|
+
<td><%= job.error %></td>
|
22
|
+
<td><pre><%= JSON.pretty_generate(job.serialized_params) %></pre></td>
|
23
|
+
</tr>
|
24
|
+
<% end %>
|
25
|
+
</tbody>
|
26
|
+
</table>
|
27
|
+
</div>
|
26
28
|
</div>
|
data/lib/good_job.rb
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
require "rails"
|
2
|
-
|
3
2
|
require "active_job"
|
4
3
|
require "active_job/queue_adapters"
|
5
4
|
|
6
5
|
require "zeitwerk"
|
7
|
-
|
8
|
-
loader
|
9
|
-
|
10
|
-
|
11
|
-
)
|
12
|
-
loader.
|
13
|
-
|
6
|
+
Zeitwerk::Loader.for_gem.tap do |loader|
|
7
|
+
loader.inflector.inflect({
|
8
|
+
"cli" => "CLI",
|
9
|
+
})
|
10
|
+
loader.ignore(File.join(File.dirname(__FILE__), "generators"))
|
11
|
+
loader.setup
|
12
|
+
end
|
14
13
|
|
15
14
|
require "good_job/railtie"
|
16
15
|
|
@@ -58,9 +58,7 @@ module GoodJob
|
|
58
58
|
def rails_execution_mode
|
59
59
|
if execution_mode(default: nil)
|
60
60
|
execution_mode
|
61
|
-
elsif Rails.env.development?
|
62
|
-
:inline
|
63
|
-
elsif Rails.env.test?
|
61
|
+
elsif Rails.env.development? || Rails.env.test?
|
64
62
|
:inline
|
65
63
|
else
|
66
64
|
:external
|
@@ -103,6 +101,9 @@ module GoodJob
|
|
103
101
|
).to_i
|
104
102
|
end
|
105
103
|
|
104
|
+
# Number of seconds to preserve jobs when using the +good_job cleanup_preserved_jobs+ CLI command.
|
105
|
+
# This configuration is only used when {GoodJob.preserve_job_records} is +true+.
|
106
|
+
# @return [Boolean]
|
106
107
|
def cleanup_preserved_jobs_before_seconds_ago
|
107
108
|
(
|
108
109
|
options[:before_seconds_ago] ||
|
data/lib/good_job/job.rb
CHANGED
@@ -139,7 +139,7 @@ module GoodJob
|
|
139
139
|
unfinished.priority_ordered.only_scheduled.limit(1).with_advisory_lock do |good_jobs|
|
140
140
|
good_job = good_jobs.first
|
141
141
|
# TODO: Determine why some records are fetched without an advisory lock at all
|
142
|
-
break unless good_job&.
|
142
|
+
break unless good_job&.executable?
|
143
143
|
|
144
144
|
result, error = good_job.perform
|
145
145
|
end
|
@@ -216,6 +216,12 @@ module GoodJob
|
|
216
216
|
[result, job_error]
|
217
217
|
end
|
218
218
|
|
219
|
+
# Tests whether this job is safe to be executed by this thread.
|
220
|
+
# @return [Boolean]
|
221
|
+
def executable?
|
222
|
+
self.class.unscoped.unfinished.owns_advisory_locked.exists?(id: id)
|
223
|
+
end
|
224
|
+
|
219
225
|
private
|
220
226
|
|
221
227
|
def execute
|
data/lib/good_job/lockable.rb
CHANGED
@@ -32,11 +32,18 @@ module GoodJob
|
|
32
32
|
original_query = self
|
33
33
|
|
34
34
|
cte_table = Arel::Table.new(:rows)
|
35
|
-
|
35
|
+
cte_query = original_query.select(primary_key).except(:limit)
|
36
|
+
cte_type = if supports_cte_materialization_specifiers?
|
37
|
+
'MATERIALIZED'
|
38
|
+
else
|
39
|
+
''
|
40
|
+
end
|
41
|
+
|
42
|
+
composed_cte = Arel::Nodes::As.new(cte_table, Arel::Nodes::SqlLiteral.new([cte_type, "(", cte_query.to_sql, ")"].join(' ')))
|
36
43
|
|
37
44
|
query = cte_table.project(cte_table[:id])
|
38
|
-
|
39
|
-
|
45
|
+
.with(composed_cte)
|
46
|
+
.where(Arel.sql(sanitize_sql_for_conditions(["pg_try_advisory_lock(('x' || substr(md5(:table_name || #{connection.quote_table_name(cte_table.name)}.#{quoted_primary_key}::text), 1, 16))::bit(64)::bigint)", { table_name: table_name }])))
|
40
47
|
|
41
48
|
limit = original_query.arel.ast.limit
|
42
49
|
query.limit = limit.value if limit.present?
|
@@ -132,6 +139,12 @@ module GoodJob
|
|
132
139
|
records.each(&:advisory_unlock)
|
133
140
|
end
|
134
141
|
end
|
142
|
+
|
143
|
+
def supports_cte_materialization_specifiers?
|
144
|
+
return @_supports_cte_materialization_specifiers if defined?(@_supports_cte_materialization_specifiers)
|
145
|
+
|
146
|
+
@_supports_cte_materialization_specifiers = ActiveRecord::Base.connection.postgresql_version >= 120000
|
147
|
+
end
|
135
148
|
end
|
136
149
|
|
137
150
|
# Acquires an advisory lock on this record if it is not already locked by
|
@@ -140,10 +153,12 @@ module GoodJob
|
|
140
153
|
# all remaining locks).
|
141
154
|
# @return [Boolean] whether the lock was acquired.
|
142
155
|
def advisory_lock
|
143
|
-
|
144
|
-
|
156
|
+
query = <<~SQL.squish
|
157
|
+
SELECT 1 AS one
|
158
|
+
WHERE pg_try_advisory_lock(('x'||substr(md5($1 || $2::text), 1, 16))::bit(64)::bigint)
|
145
159
|
SQL
|
146
|
-
|
160
|
+
binds = [[nil, self.class.table_name], [nil, send(self.class.primary_key)]]
|
161
|
+
ActiveRecord::Base.connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Advisory Lock', binds).any?
|
147
162
|
end
|
148
163
|
|
149
164
|
# Releases an advisory lock on this record if it is locked by this database
|
@@ -151,10 +166,12 @@ module GoodJob
|
|
151
166
|
# {#advisory_unlock} and {#advisory_lock} the same number of times.
|
152
167
|
# @return [Boolean] whether the lock was released.
|
153
168
|
def advisory_unlock
|
154
|
-
|
155
|
-
|
169
|
+
query = <<~SQL.squish
|
170
|
+
SELECT 1 AS one
|
171
|
+
WHERE pg_advisory_unlock(('x'||substr(md5($1 || $2::text), 1, 16))::bit(64)::bigint)
|
156
172
|
SQL
|
157
|
-
|
173
|
+
binds = [[nil, self.class.table_name], [nil, send(self.class.primary_key)]]
|
174
|
+
self.class.connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Advisory Unlock', binds).any?
|
158
175
|
end
|
159
176
|
|
160
177
|
# Acquires an advisory lock on this record or raises
|
@@ -191,13 +208,32 @@ module GoodJob
|
|
191
208
|
# Tests whether this record has an advisory lock on it.
|
192
209
|
# @return [Boolean]
|
193
210
|
def advisory_locked?
|
194
|
-
|
211
|
+
query = <<~SQL.squish
|
212
|
+
SELECT 1 AS one
|
213
|
+
FROM pg_locks
|
214
|
+
WHERE pg_locks.locktype = 'advisory'
|
215
|
+
AND pg_locks.objsubid = 1
|
216
|
+
AND pg_locks.classid = ('x' || substr(md5($1 || $2::text), 1, 16))::bit(32)::int
|
217
|
+
AND pg_locks.objid = (('x' || substr(md5($3 || $4::text), 1, 16))::bit(64) << 32)::bit(32)::int
|
218
|
+
SQL
|
219
|
+
binds = [[nil, self.class.table_name], [nil, send(self.class.primary_key)], [nil, self.class.table_name], [nil, send(self.class.primary_key)]]
|
220
|
+
self.class.connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Advisory Locked?', binds).any?
|
195
221
|
end
|
196
222
|
|
197
223
|
# Tests whether this record is locked by the current database session.
|
198
224
|
# @return [Boolean]
|
199
225
|
def owns_advisory_lock?
|
200
|
-
|
226
|
+
query = <<~SQL.squish
|
227
|
+
SELECT 1 AS one
|
228
|
+
FROM pg_locks
|
229
|
+
WHERE pg_locks.locktype = 'advisory'
|
230
|
+
AND pg_locks.objsubid = 1
|
231
|
+
AND pg_locks.classid = ('x' || substr(md5($1 || $2::text), 1, 16))::bit(32)::int
|
232
|
+
AND pg_locks.objid = (('x' || substr(md5($3 || $4::text), 1, 16))::bit(64) << 32)::bit(32)::int
|
233
|
+
AND pg_locks.pid = pg_backend_pid()
|
234
|
+
SQL
|
235
|
+
binds = [[nil, self.class.table_name], [nil, send(self.class.primary_key)], [nil, self.class.table_name], [nil, send(self.class.primary_key)]]
|
236
|
+
self.class.connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Owns Advisory Lock?', binds).any?
|
201
237
|
end
|
202
238
|
|
203
239
|
# Releases all advisory locks on the record that are held by the current
|
@@ -213,5 +249,14 @@ module GoodJob
|
|
213
249
|
# Made public in Rails 5.2
|
214
250
|
self.class.send(:sanitize_sql_for_conditions, *args)
|
215
251
|
end
|
252
|
+
|
253
|
+
def pg_or_jdbc_query(query)
|
254
|
+
if Concurrent.on_jruby?
|
255
|
+
# Replace $1 bind parameters with ?
|
256
|
+
query.gsub(/\$\d*/, '?')
|
257
|
+
else
|
258
|
+
query
|
259
|
+
end
|
260
|
+
end
|
216
261
|
end
|
217
262
|
end
|
@@ -218,13 +218,13 @@ module GoodJob
|
|
218
218
|
#
|
219
219
|
%w(info debug warn error fatal unknown).each do |level|
|
220
220
|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
221
|
-
def #{level}(progname = nil, tags: [], &block)
|
222
|
-
return unless logger
|
223
|
-
|
224
|
-
tag_logger(*tags) do
|
225
|
-
logger.#{level}(progname, &block)
|
226
|
-
end
|
227
|
-
end
|
221
|
+
def #{level}(progname = nil, tags: [], &block) # def info(progname = nil, tags: [], &block)
|
222
|
+
return unless logger # return unless logger
|
223
|
+
#
|
224
|
+
tag_logger(*tags) do # tag_logger(*tags) do
|
225
|
+
logger.#{level}(progname, &block) # logger.info(progname, &block)
|
226
|
+
end # end
|
227
|
+
end #
|
228
228
|
METHOD
|
229
229
|
end
|
230
230
|
end
|
data/lib/good_job/notifier.rb
CHANGED
@@ -9,6 +9,9 @@ module GoodJob # :nodoc:
|
|
9
9
|
# When a message is received, the notifier passes the message to each of its recipients.
|
10
10
|
#
|
11
11
|
class Notifier
|
12
|
+
# Raised if the Database adapter does not implement LISTEN.
|
13
|
+
AdapterCannotListenError = Class.new(StandardError)
|
14
|
+
|
12
15
|
# Default Postgres channel for LISTEN/NOTIFY
|
13
16
|
CHANNEL = 'good_job'.freeze
|
14
17
|
# Defaults for instance of Concurrent::ThreadPoolExecutor
|
@@ -90,6 +93,20 @@ module GoodJob # :nodoc:
|
|
90
93
|
!@pool.running?
|
91
94
|
end
|
92
95
|
|
96
|
+
# Invoked on completion of ThreadPoolExecutor task
|
97
|
+
# @!visibility private
|
98
|
+
# @return [void]
|
99
|
+
def listen_observer(_time, _result, thread_error)
|
100
|
+
return if thread_error.is_a? AdapterCannotListenError
|
101
|
+
|
102
|
+
if thread_error
|
103
|
+
GoodJob.on_thread_error.call(thread_error) if GoodJob.on_thread_error.respond_to?(:call)
|
104
|
+
ActiveSupport::Notifications.instrument("notifier_notify_error.good_job", { error: thread_error })
|
105
|
+
end
|
106
|
+
|
107
|
+
listen unless shutdown?
|
108
|
+
end
|
109
|
+
|
93
110
|
private
|
94
111
|
|
95
112
|
def create_pool
|
@@ -100,7 +117,7 @@ module GoodJob # :nodoc:
|
|
100
117
|
future = Concurrent::Future.new(args: [@recipients, @pool, @listening], executor: @pool) do |recipients, pool, listening|
|
101
118
|
with_listen_connection do |conn|
|
102
119
|
ActiveSupport::Notifications.instrument("notifier_listen.good_job") do
|
103
|
-
conn.async_exec
|
120
|
+
conn.async_exec("LISTEN #{CHANNEL}").clear
|
104
121
|
end
|
105
122
|
|
106
123
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
@@ -120,14 +137,11 @@ module GoodJob # :nodoc:
|
|
120
137
|
listening.make_false
|
121
138
|
end
|
122
139
|
end
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
@listening.make_false
|
129
|
-
ActiveSupport::Notifications.instrument("notifier_unlisten.good_job") do
|
130
|
-
conn.async_exec "UNLISTEN *"
|
140
|
+
ensure
|
141
|
+
listening.make_false
|
142
|
+
ActiveSupport::Notifications.instrument("notifier_unlisten.good_job") do
|
143
|
+
conn.async_exec("UNLISTEN *").clear
|
144
|
+
end
|
131
145
|
end
|
132
146
|
end
|
133
147
|
|
@@ -135,16 +149,14 @@ module GoodJob # :nodoc:
|
|
135
149
|
future.execute
|
136
150
|
end
|
137
151
|
|
138
|
-
def listen_observer(_time, _result, _thread_error)
|
139
|
-
listen unless shutdown?
|
140
|
-
end
|
141
|
-
|
142
152
|
def with_listen_connection
|
143
153
|
ar_conn = ActiveRecord::Base.connection_pool.checkout.tap do |conn|
|
144
154
|
ActiveRecord::Base.connection_pool.remove(conn)
|
145
155
|
end
|
146
156
|
pg_conn = ar_conn.raw_connection
|
147
|
-
|
157
|
+
raise AdapterCannotListenError unless pg_conn.respond_to? :wait_for_notify
|
158
|
+
|
159
|
+
pg_conn.async_exec("SET application_name = #{pg_conn.escape_identifier(self.class.name)}").clear
|
148
160
|
yield pg_conn
|
149
161
|
ensure
|
150
162
|
ar_conn&.disconnect!
|
data/lib/good_job/poller.rb
CHANGED
@@ -19,6 +19,9 @@ module GoodJob # :nodoc:
|
|
19
19
|
# @return [array<GoodJob:Poller>]
|
20
20
|
cattr_reader :instances, default: [], instance_reader: false
|
21
21
|
|
22
|
+
# Creates GoodJob::Poller from a GoodJob::Configuration instance.
|
23
|
+
# @param configuration [GoodJob::Configuration]
|
24
|
+
# @return [GoodJob::Poller]
|
22
25
|
def self.from_configuration(configuration)
|
23
26
|
GoodJob::Poller.new(poll_interval: configuration.poll_interval)
|
24
27
|
end
|
data/lib/good_job/scheduler.rb
CHANGED
@@ -22,7 +22,7 @@ module GoodJob # :nodoc:
|
|
22
22
|
max_threads: Configuration::DEFAULT_MAX_THREADS,
|
23
23
|
auto_terminate: true,
|
24
24
|
idletime: 60,
|
25
|
-
max_queue:
|
25
|
+
max_queue: 0,
|
26
26
|
fallback_policy: :discard,
|
27
27
|
}.freeze
|
28
28
|
|
@@ -170,10 +170,13 @@ module GoodJob # :nodoc:
|
|
170
170
|
# @return [Integer]
|
171
171
|
def ready_worker_count
|
172
172
|
synchronize do
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
173
|
+
if Concurrent.on_jruby?
|
174
|
+
@executor.getMaximumPoolSize - @executor.getActiveCount
|
175
|
+
else
|
176
|
+
workers_still_to_be_created = @max_length - @pool.length
|
177
|
+
workers_created_but_waiting = @ready.length
|
178
|
+
workers_still_to_be_created + workers_created_but_waiting
|
179
|
+
end
|
177
180
|
end
|
178
181
|
end
|
179
182
|
end
|
data/lib/good_job/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: good_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Sheldon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -52,20 +52,6 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 1.0.2
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: pg
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 1.0.0
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 1.0.0
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: railties
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,20 +150,6 @@ dependencies:
|
|
164
150
|
- - ">="
|
165
151
|
- !ruby/object:Gem::Version
|
166
152
|
version: '0'
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: erb_lint
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - ">="
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: '0'
|
174
|
-
type: :development
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - ">="
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: '0'
|
181
153
|
- !ruby/object:Gem::Dependency
|
182
154
|
name: foreman
|
183
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -248,20 +220,6 @@ dependencies:
|
|
248
220
|
- - ">="
|
249
221
|
- !ruby/object:Gem::Version
|
250
222
|
version: '0'
|
251
|
-
- !ruby/object:Gem::Dependency
|
252
|
-
name: mdl
|
253
|
-
requirement: !ruby/object:Gem::Requirement
|
254
|
-
requirements:
|
255
|
-
- - ">="
|
256
|
-
- !ruby/object:Gem::Version
|
257
|
-
version: '0'
|
258
|
-
type: :development
|
259
|
-
prerelease: false
|
260
|
-
version_requirements: !ruby/object:Gem::Requirement
|
261
|
-
requirements:
|
262
|
-
- - ">="
|
263
|
-
- !ruby/object:Gem::Version
|
264
|
-
version: '0'
|
265
223
|
- !ruby/object:Gem::Dependency
|
266
224
|
name: pry-rails
|
267
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -290,34 +248,6 @@ dependencies:
|
|
290
248
|
- - ">="
|
291
249
|
- !ruby/object:Gem::Version
|
292
250
|
version: '0'
|
293
|
-
- !ruby/object:Gem::Dependency
|
294
|
-
name: rails
|
295
|
-
requirement: !ruby/object:Gem::Requirement
|
296
|
-
requirements:
|
297
|
-
- - ">="
|
298
|
-
- !ruby/object:Gem::Version
|
299
|
-
version: '0'
|
300
|
-
type: :development
|
301
|
-
prerelease: false
|
302
|
-
version_requirements: !ruby/object:Gem::Requirement
|
303
|
-
requirements:
|
304
|
-
- - ">="
|
305
|
-
- !ruby/object:Gem::Version
|
306
|
-
version: '0'
|
307
|
-
- !ruby/object:Gem::Dependency
|
308
|
-
name: rbtrace
|
309
|
-
requirement: !ruby/object:Gem::Requirement
|
310
|
-
requirements:
|
311
|
-
- - ">="
|
312
|
-
- !ruby/object:Gem::Version
|
313
|
-
version: '0'
|
314
|
-
type: :development
|
315
|
-
prerelease: false
|
316
|
-
version_requirements: !ruby/object:Gem::Requirement
|
317
|
-
requirements:
|
318
|
-
- - ">="
|
319
|
-
- !ruby/object:Gem::Version
|
320
|
-
version: '0'
|
321
251
|
- !ruby/object:Gem::Dependency
|
322
252
|
name: rspec-rails
|
323
253
|
requirement: !ruby/object:Gem::Requirement
|
@@ -332,62 +262,6 @@ dependencies:
|
|
332
262
|
- - ">="
|
333
263
|
- !ruby/object:Gem::Version
|
334
264
|
version: '0'
|
335
|
-
- !ruby/object:Gem::Dependency
|
336
|
-
name: rubocop
|
337
|
-
requirement: !ruby/object:Gem::Requirement
|
338
|
-
requirements:
|
339
|
-
- - ">="
|
340
|
-
- !ruby/object:Gem::Version
|
341
|
-
version: '0'
|
342
|
-
type: :development
|
343
|
-
prerelease: false
|
344
|
-
version_requirements: !ruby/object:Gem::Requirement
|
345
|
-
requirements:
|
346
|
-
- - ">="
|
347
|
-
- !ruby/object:Gem::Version
|
348
|
-
version: '0'
|
349
|
-
- !ruby/object:Gem::Dependency
|
350
|
-
name: rubocop-performance
|
351
|
-
requirement: !ruby/object:Gem::Requirement
|
352
|
-
requirements:
|
353
|
-
- - ">="
|
354
|
-
- !ruby/object:Gem::Version
|
355
|
-
version: '0'
|
356
|
-
type: :development
|
357
|
-
prerelease: false
|
358
|
-
version_requirements: !ruby/object:Gem::Requirement
|
359
|
-
requirements:
|
360
|
-
- - ">="
|
361
|
-
- !ruby/object:Gem::Version
|
362
|
-
version: '0'
|
363
|
-
- !ruby/object:Gem::Dependency
|
364
|
-
name: rubocop-rails
|
365
|
-
requirement: !ruby/object:Gem::Requirement
|
366
|
-
requirements:
|
367
|
-
- - ">="
|
368
|
-
- !ruby/object:Gem::Version
|
369
|
-
version: '0'
|
370
|
-
type: :development
|
371
|
-
prerelease: false
|
372
|
-
version_requirements: !ruby/object:Gem::Requirement
|
373
|
-
requirements:
|
374
|
-
- - ">="
|
375
|
-
- !ruby/object:Gem::Version
|
376
|
-
version: '0'
|
377
|
-
- !ruby/object:Gem::Dependency
|
378
|
-
name: rubocop-rspec
|
379
|
-
requirement: !ruby/object:Gem::Requirement
|
380
|
-
requirements:
|
381
|
-
- - ">="
|
382
|
-
- !ruby/object:Gem::Version
|
383
|
-
version: '0'
|
384
|
-
type: :development
|
385
|
-
prerelease: false
|
386
|
-
version_requirements: !ruby/object:Gem::Requirement
|
387
|
-
requirements:
|
388
|
-
- - ">="
|
389
|
-
- !ruby/object:Gem::Version
|
390
|
-
version: '0'
|
391
265
|
- !ruby/object:Gem::Dependency
|
392
266
|
name: selenium-webdriver
|
393
267
|
requirement: !ruby/object:Gem::Requirement
|
@@ -458,20 +332,20 @@ files:
|
|
458
332
|
- CHANGELOG.md
|
459
333
|
- LICENSE.txt
|
460
334
|
- README.md
|
335
|
+
- engine/app/assets/style.css
|
336
|
+
- engine/app/assets/vendor/bootstrap/bootstrap-native.js
|
337
|
+
- engine/app/assets/vendor/bootstrap/bootstrap.css
|
338
|
+
- engine/app/assets/vendor/chartist/chartist.css
|
339
|
+
- engine/app/assets/vendor/chartist/chartist.js
|
461
340
|
- engine/app/controllers/good_job/active_jobs_controller.rb
|
462
341
|
- engine/app/controllers/good_job/base_controller.rb
|
463
342
|
- engine/app/controllers/good_job/dashboards_controller.rb
|
464
343
|
- engine/app/helpers/good_job/application_helper.rb
|
465
|
-
- engine/app/views/assets/_style.css.erb
|
466
344
|
- engine/app/views/good_job/active_jobs/show.html.erb
|
467
345
|
- engine/app/views/good_job/dashboards/index.html.erb
|
468
346
|
- engine/app/views/layouts/good_job/base.html.erb
|
469
347
|
- engine/app/views/shared/_chart.erb
|
470
348
|
- engine/app/views/shared/_jobs_table.erb
|
471
|
-
- engine/app/views/vendor/bootstrap/_bootstrap-native.js.erb
|
472
|
-
- engine/app/views/vendor/bootstrap/_bootstrap.css.erb
|
473
|
-
- engine/app/views/vendor/chartist/_chartist.css.erb
|
474
|
-
- engine/app/views/vendor/chartist/_chartist.js.erb
|
475
349
|
- engine/config/routes.rb
|
476
350
|
- engine/lib/good_job/engine.rb
|
477
351
|
- exe/good_job
|
@@ -525,7 +399,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
525
399
|
- !ruby/object:Gem::Version
|
526
400
|
version: '0'
|
527
401
|
requirements: []
|
528
|
-
rubygems_version: 3.
|
402
|
+
rubygems_version: 3.2.4
|
529
403
|
signing_key:
|
530
404
|
specification_version: 4
|
531
405
|
summary: A multithreaded, Postgres-based ActiveJob backend for Ruby on Rails
|