good_job 3.1.0 → 3.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +62 -7
- data/README.md +35 -31
- data/app/assets/good_job/modules/application.js +2 -0
- data/app/assets/good_job/modules/popovers.js +7 -0
- data/app/assets/good_job/style.css +4 -0
- data/app/helpers/good_job/application_helper.rb +2 -2
- data/{lib → app/models/concerns}/good_job/filterable.rb +0 -0
- data/app/models/concerns/good_job/reportable.rb +43 -0
- data/{lib → app}/models/good_job/active_job_job.rb +0 -0
- data/{lib → app}/models/good_job/base_record.rb +0 -0
- data/{lib → app}/models/good_job/cron_entry.rb +1 -1
- data/{lib → app}/models/good_job/execution.rb +42 -45
- data/{lib → app/models}/good_job/execution_result.rb +0 -0
- data/{lib → app}/models/good_job/job.rb +2 -27
- data/{lib → app}/models/good_job/lockable.rb +0 -0
- data/{lib → app}/models/good_job/process.rb +4 -0
- data/app/views/good_job/cron_entries/index.html.erb +60 -57
- data/app/views/good_job/jobs/_executions.erb +31 -28
- data/app/views/good_job/jobs/_table.erb +138 -109
- data/app/views/good_job/jobs/show.html.erb +40 -31
- data/app/views/good_job/processes/index.html.erb +60 -32
- data/app/views/good_job/shared/_navbar.erb +1 -1
- data/app/views/good_job/shared/icons/_dots.html.erb +3 -0
- data/app/views/good_job/shared/icons/_info.html.erb +4 -0
- data/lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb +4 -4
- data/lib/generators/good_job/templates/update/migrations/01_create_good_jobs.rb.erb +4 -4
- data/lib/good_job/adapter.rb +13 -11
- data/lib/good_job/cli.rb +4 -4
- data/lib/good_job/configuration.rb +6 -1
- data/lib/good_job/daemon.rb +2 -2
- data/lib/good_job/job_performer.rb +1 -1
- data/lib/good_job/notifier.rb +1 -0
- data/lib/good_job/version.rb +1 -1
- data/lib/good_job.rb +29 -14
- metadata +19 -30
- data/lib/good_job/active_job_extensions.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cabb124450eb5e88a460635fb4aa70f3e5a53406ded6554bb32018fa2aa890bc
|
4
|
+
data.tar.gz: 0d83085806f8a1f30eff6136df4995f7982064b90a497ee56a4f8b9d922f4fbb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f17d4379517d9909ac771c9920b3472b1d5bbb18ce45bd78b160f76eba6b6a1169e6b89ec044cd8f3c5ad93a311be45174bd43b99468c5ff9a5c4bad088263f
|
7
|
+
data.tar.gz: 27f6aa3048d4035feb1e55b7cd4a3ba8410deb74ec9268fba23bac9a75c9db26bc3599d1f140bf68182b2f2307183013bc6601927a6eec19cab6051fcf03a927
|
data/CHANGELOG.md
CHANGED
@@ -1,12 +1,70 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v3.3.1](https://github.com/bensheldon/good_job/tree/v3.3.1) (2022-07-26)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.3.0...v3.3.1)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Show basename of proctitle [\#679](https://github.com/bensheldon/good_job/pull/679) ([bkeepers](https://github.com/bkeepers))
|
10
|
+
|
11
|
+
**Fixed bugs:**
|
12
|
+
|
13
|
+
- Only count \_active\_ processes in the Navbar [\#680](https://github.com/bensheldon/good_job/pull/680) ([bensheldon](https://github.com/bensheldon))
|
14
|
+
- Remove Zeitwerk and use explicit requires to be more like an engine [\#677](https://github.com/bensheldon/good_job/pull/677) ([bensheldon](https://github.com/bensheldon))
|
15
|
+
|
16
|
+
**Closed issues:**
|
17
|
+
|
18
|
+
- Dashboard UI Invalid count of running process [\#678](https://github.com/bensheldon/good_job/issues/678)
|
19
|
+
|
20
|
+
**Merged pull requests:**
|
21
|
+
|
22
|
+
- Lock to dotenv 2.7.x for Ruby 2.5 compatibility [\#682](https://github.com/bensheldon/good_job/pull/682) ([bensheldon](https://github.com/bensheldon))
|
23
|
+
- Create global GoodJob.configuration object [\#681](https://github.com/bensheldon/good_job/pull/681) ([bensheldon](https://github.com/bensheldon))
|
24
|
+
|
25
|
+
## [v3.3.0](https://github.com/bensheldon/good_job/tree/v3.3.0) (2022-07-24)
|
26
|
+
|
27
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.2.0...v3.3.0)
|
28
|
+
|
29
|
+
**Implemented enhancements:**
|
30
|
+
|
31
|
+
- Dashboard: Update cron and processes to match jobs listing [\#676](https://github.com/bensheldon/good_job/pull/676) ([bkeepers](https://github.com/bkeepers))
|
32
|
+
- Dashboard: improvements to jobs index and show pages [\#672](https://github.com/bensheldon/good_job/pull/672) ([bkeepers](https://github.com/bkeepers))
|
33
|
+
|
34
|
+
**Fixed bugs:**
|
35
|
+
|
36
|
+
- Replace "timestamp" column-type in migrations with "datetime" [\#671](https://github.com/bensheldon/good_job/pull/671) ([bensheldon](https://github.com/bensheldon))
|
37
|
+
|
38
|
+
**Closed issues:**
|
39
|
+
|
40
|
+
- Calculating database connections [\#669](https://github.com/bensheldon/good_job/issues/669)
|
41
|
+
- Unable to Replace GoodJob's Logger [\#667](https://github.com/bensheldon/good_job/issues/667)
|
42
|
+
- Readme should consistently encourage usage of `config.good_job....` instead of `GoodJob.` configuration [\#628](https://github.com/bensheldon/good_job/issues/628)
|
43
|
+
- Improve the "Gem development" section of README? [\#551](https://github.com/bensheldon/good_job/issues/551)
|
44
|
+
- Simplify Rails initialization to only be a mountable Engine [\#543](https://github.com/bensheldon/good_job/issues/543)
|
45
|
+
|
46
|
+
**Merged pull requests:**
|
47
|
+
|
48
|
+
- Improve Readme description of v3 job preservation defaults [\#670](https://github.com/bensheldon/good_job/pull/670) ([bensheldon](https://github.com/bensheldon))
|
49
|
+
- update Gemfile.lock to latest dependencies [\#647](https://github.com/bensheldon/good_job/pull/647) ([jrochkind](https://github.com/jrochkind))
|
50
|
+
|
51
|
+
## [v3.2.0](https://github.com/bensheldon/good_job/tree/v3.2.0) (2022-07-12)
|
52
|
+
|
53
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.1.0...v3.2.0)
|
54
|
+
|
55
|
+
**Implemented enhancements:**
|
56
|
+
|
57
|
+
- Ordered queue handling by workers [\#665](https://github.com/bensheldon/good_job/pull/665) ([jrochkind](https://github.com/jrochkind))
|
58
|
+
|
3
59
|
## [v3.1.0](https://github.com/bensheldon/good_job/tree/v3.1.0) (2022-07-11)
|
4
60
|
|
5
61
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.0.2...v3.1.0)
|
6
62
|
|
7
63
|
**Implemented enhancements:**
|
8
64
|
|
65
|
+
- Show job/cron/process counts in the Navbar [\#663](https://github.com/bensheldon/good_job/pull/663) ([bensheldon](https://github.com/bensheldon))
|
9
66
|
- Improve Dashboard display of parameters \(CronEntry kwargs; Process configuration; Job and Execution database values\) [\#662](https://github.com/bensheldon/good_job/pull/662) ([bensheldon](https://github.com/bensheldon))
|
67
|
+
- Dequeing should be first-in first-out [\#651](https://github.com/bensheldon/good_job/pull/651) ([jrochkind](https://github.com/jrochkind))
|
10
68
|
|
11
69
|
**Fixed bugs:**
|
12
70
|
|
@@ -19,11 +77,6 @@
|
|
19
77
|
- Cron schedule page in dashboard not showing kwargs [\#608](https://github.com/bensheldon/good_job/issues/608)
|
20
78
|
- Paralelism x database connections [\#569](https://github.com/bensheldon/good_job/issues/569)
|
21
79
|
|
22
|
-
**Merged pull requests:**
|
23
|
-
|
24
|
-
- Show job/cron/process counts in the Navbar [\#663](https://github.com/bensheldon/good_job/pull/663) ([bensheldon](https://github.com/bensheldon))
|
25
|
-
- Dequeing should be first-in first-out [\#651](https://github.com/bensheldon/good_job/pull/651) ([jrochkind](https://github.com/jrochkind))
|
26
|
-
|
27
80
|
## [v3.0.2](https://github.com/bensheldon/good_job/tree/v3.0.2) (2022-07-10)
|
28
81
|
|
29
82
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.0.1...v3.0.2)
|
@@ -53,13 +106,16 @@
|
|
53
106
|
|
54
107
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.0.0...v3.0.1)
|
55
108
|
|
109
|
+
**Fixed bugs:**
|
110
|
+
|
111
|
+
- Fix `GoodJob.cleanup_preserved_jobs` to use `delete_all` instead of `destroy_all` [\#652](https://github.com/bensheldon/good_job/pull/652) ([bensheldon](https://github.com/bensheldon))
|
112
|
+
|
56
113
|
**Closed issues:**
|
57
114
|
|
58
115
|
- ERROR: relation "good\_jobs" does not exist at character 454 [\#308](https://github.com/bensheldon/good_job/issues/308)
|
59
116
|
|
60
117
|
**Merged pull requests:**
|
61
118
|
|
62
|
-
- Fix `GoodJob.cleanup_preserved_jobs` to use `delete_all` instead of `destroy_all` [\#652](https://github.com/bensheldon/good_job/pull/652) ([bensheldon](https://github.com/bensheldon))
|
63
119
|
- Create codeql-analysis.yml [\#648](https://github.com/bensheldon/good_job/pull/648) ([bensheldon](https://github.com/bensheldon))
|
64
120
|
|
65
121
|
## [v3.0.0](https://github.com/bensheldon/good_job/tree/v3.0.0) (2022-06-26)
|
@@ -1047,7 +1103,6 @@
|
|
1047
1103
|
- PgBouncer and prepared statements [\#269](https://github.com/bensheldon/good_job/issues/269)
|
1048
1104
|
- Question about locking internals [\#212](https://github.com/bensheldon/good_job/issues/212)
|
1049
1105
|
- Encoding::UndefinedConversionError \("\xE2" from ASCII-8BIT to UTF-8\) [\#198](https://github.com/bensheldon/good_job/issues/198)
|
1050
|
-
- tools for managing a 'fleet' of processes [\#150](https://github.com/bensheldon/good_job/issues/150)
|
1051
1106
|
|
1052
1107
|
**Merged pull requests:**
|
1053
1108
|
|
data/README.md
CHANGED
@@ -117,7 +117,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
117
117
|
YourJob.set(queue: :some_queue, wait: 5.minutes, priority: 10).perform_later
|
118
118
|
```
|
119
119
|
|
120
|
-
1. In development, GoodJob executes jobs immediately in a separate thread (async mode). In production, GoodJob provides different options:
|
120
|
+
1. In development, GoodJob executes jobs immediately in a separate thread ("async" mode). In production, GoodJob provides different options:
|
121
121
|
|
122
122
|
- By default, GoodJob separates job enqueuing from job execution so that jobs can be scaled independently of the web server. Use the GoodJob command-line tool to execute jobs:
|
123
123
|
|
@@ -199,7 +199,7 @@ Usage:
|
|
199
199
|
good_job cleanup_preserved_jobs
|
200
200
|
|
201
201
|
Options:
|
202
|
-
[--before-seconds-ago=SECONDS] # Destroy records finished more than this many seconds ago (env var: GOOD_JOB_CLEANUP_PRESERVED_JOBS_BEFORE_SECONDS_AGO, default:
|
202
|
+
[--before-seconds-ago=SECONDS] # Destroy records finished more than this many seconds ago (env var: GOOD_JOB_CLEANUP_PRESERVED_JOBS_BEFORE_SECONDS_AGO, default: 1209600 (14 days))
|
203
203
|
|
204
204
|
Destroys preserved job records.
|
205
205
|
|
@@ -226,6 +226,8 @@ GoodJob configuration can be placed within Rails `config` directory for all envi
|
|
226
226
|
Configuration examples:
|
227
227
|
|
228
228
|
```ruby
|
229
|
+
# config/initializers/good_job.rb OR config/application.rb OR config/environments/{RAILS_ENV}.rb
|
230
|
+
|
229
231
|
Rails.application.configure do
|
230
232
|
# Configure options individually...
|
231
233
|
config.good_job.preserve_job_records = true
|
@@ -275,9 +277,9 @@ Available configuration options are:
|
|
275
277
|
- `enable_cron` (boolean) whether to run cron process. Defaults to `false`. You can also set this with the environment variable `GOOD_JOB_ENABLE_CRON`.
|
276
278
|
- `cron` (hash) cron configuration. Defaults to `{}`. You can also set this as a JSON string with the environment variable `GOOD_JOB_CRON`
|
277
279
|
- `cleanup_discarded_jobs` (boolean) whether to destroy discarded jobs when cleaning up preserved jobs using the `$ good_job cleanup_preserved_jobs` CLI command or calling `GoodJob.cleanup_preserved_jobs`. Defaults to `true`. Can also be set with the environment variable `GOOD_JOB_CLEANUP_DISCARDED_JOBS`. _This configuration is only used when {GoodJob.preserve_job_records} is `true`._
|
278
|
-
- `cleanup_preserved_jobs_before_seconds_ago` (integer) number of seconds to preserve jobs when using the `$ good_job cleanup_preserved_jobs` CLI command or calling `GoodJob.cleanup_preserved_jobs`. Defaults to `
|
279
|
-
- `cleanup_interval_jobs` (integer) Number of jobs a Scheduler will execute before cleaning up preserved jobs. Defaults to `
|
280
|
-
- `cleanup_interval_seconds` (integer) Number of seconds a Scheduler will wait before cleaning up preserved jobs. Defaults to `
|
280
|
+
- `cleanup_preserved_jobs_before_seconds_ago` (integer) number of seconds to preserve jobs when using the `$ good_job cleanup_preserved_jobs` CLI command or calling `GoodJob.cleanup_preserved_jobs`. Defaults to `1209600` (14 days). Can also be set with the environment variable `GOOD_JOB_CLEANUP_PRESERVED_JOBS_BEFORE_SECONDS_AGO`. _This configuration is only used when {GoodJob.preserve_job_records} is `true`._
|
281
|
+
- `cleanup_interval_jobs` (integer) Number of jobs a Scheduler will execute before cleaning up preserved jobs. Defaults to `1000`. Can also be set with the environment variable `GOOD_JOB_CLEANUP_INTERVAL_JOBS`.
|
282
|
+
- `cleanup_interval_seconds` (integer) Number of seconds a Scheduler will wait before cleaning up preserved jobs. Defaults to `600` (10 minutes). Can also be set with the environment variable `GOOD_JOB_CLEANUP_INTERVAL_SECONDS`.
|
281
283
|
- `inline_execution_respects_schedule` (boolean) Opt-in to future behavior of inline execution respecting scheduled jobs. Defaults to `false`.
|
282
284
|
- `logger` ([Rails Logger](https://api.rubyonrails.org/classes/ActiveSupport/Logger.html)) lets you set a custom logger for GoodJob. It should be an instance of a Rails `Logger` (Default: `Rails.logger`).
|
283
285
|
- `preserve_job_records` (boolean) keeps job records in your database even after jobs are completed. (Default: `true`)
|
@@ -310,21 +312,21 @@ config.good_job.execution_mode = :external
|
|
310
312
|
Good Job’s general behavior can also be configured via attributes directly on the `GoodJob` module:
|
311
313
|
|
312
314
|
- **`GoodJob.active_record_parent_class`** (string) The ActiveRecord parent class inherited by GoodJob's ActiveRecord model `GoodJob::Job` (defaults to `"ActiveRecord::Base"`). Configure this when using [multiple databases with ActiveRecord](https://guides.rubyonrails.org/active_record_multiple_databases.html) or when other custom configuration is necessary for the ActiveRecord model to connect to the Postgres database. _The value must be a String to avoid premature initialization of ActiveRecord._
|
313
|
-
- **`GoodJob.logger`** ([Rails Logger](https://api.rubyonrails.org/classes/ActiveSupport/Logger.html)) lets you set a custom logger for GoodJob. It should be an instance of a Rails `Logger`.
|
314
|
-
- **`GoodJob.preserve_job_records`** (boolean) keeps job records in your database even after jobs are completed. (Default: `true`)
|
315
|
-
- **`GoodJob.retry_on_unhandled_error`** (boolean) causes jobs to be re-queued and retried if they raise an instance of `StandardError`. Be advised this may lead to jobs being repeated infinitely ([see below for more on retries](#retries)). Instances of `Exception`, like SIGINT, will *always* be retried, regardless of this attribute’s value. (Default: `false`)
|
316
|
-
- **`GoodJob.on_thread_error`** (proc, lambda, or callable) will be called when an Exception. It can be useful for logging errors to bug tracking services, like Sentry or Airbrake.
|
317
315
|
|
318
316
|
You’ll generally want to configure these in `config/initializers/good_job.rb`, like so:
|
319
317
|
|
320
318
|
```ruby
|
321
319
|
# config/initializers/good_job.rb
|
322
320
|
GoodJob.active_record_parent_class = "ApplicationRecord"
|
323
|
-
GoodJob.preserve_job_records = true
|
324
|
-
GoodJob.retry_on_unhandled_error = false
|
325
|
-
GoodJob.on_thread_error = -> (exception) { Raven.capture_exception(exception) }
|
326
321
|
```
|
327
322
|
|
323
|
+
The following options are also configurable via accessors, but you are encouraged to use the configuration attributes instead because these may be deprecated and removed in the future:
|
324
|
+
|
325
|
+
- **`GoodJob.logger`** ([Rails Logger](https://api.rubyonrails.org/classes/ActiveSupport/Logger.html)) lets you set a custom logger for GoodJob. It should be an instance of a Rails `Logger`.
|
326
|
+
- **`GoodJob.preserve_job_records`** (boolean) keeps job records in your database even after jobs are completed. (Default: `true`)
|
327
|
+
- **`GoodJob.retry_on_unhandled_error`** (boolean) causes jobs to be re-queued and retried if they raise an instance of `StandardError`. Be advised this may lead to jobs being repeated infinitely ([see below for more on retries](#retries)). Instances of `Exception`, like SIGINT, will *always* be retried, regardless of this attribute’s value. (Default: `false`)
|
328
|
+
- **`GoodJob.on_thread_error`** (proc, lambda, or callable) will be called when an Exception. It can be useful for logging errors to bug tracking services, like Sentry or Airbrake.
|
329
|
+
|
328
330
|
### Dashboard
|
329
331
|
|
330
332
|
![Dashboard UI](https://github.com/bensheldon/good_job/raw/main/SCREENSHOT.png)
|
@@ -361,14 +363,7 @@ GoodJob includes a Dashboard as a mountable `Rails::Engine`.
|
|
361
363
|
end
|
362
364
|
```
|
363
365
|
|
364
|
-
|
365
|
-
|
366
|
-
```ruby
|
367
|
-
# eg in config/initializers/good_job.rb
|
368
|
-
GoodJob.preserve_job_records = true
|
369
|
-
```
|
370
|
-
|
371
|
-
See more at [Monitor and preserve worked jobs](#monitor-and-preserve-worked-jobs)
|
366
|
+
_To view finished (successful) and discarded (failed) jobs on the Dashboard, GoodJob must be configured to preserve job records. Preservation is enabled by default._
|
372
367
|
|
373
368
|
**Troubleshooting the Dashboard:** Some applications are unable to autoload the Goodjob Engine. To work around this, explicitly require the Engine at the top of your `config/application.rb` file, immediately after Rails is required and before Bundler requires the Rails' groups.
|
374
369
|
|
@@ -665,7 +660,7 @@ By default, GoodJob creates a single thread execution pool that will execute job
|
|
665
660
|
|
666
661
|
A pool is configured with the following syntax `<participating_queues>:<thread_count>`:
|
667
662
|
|
668
|
-
- `<participating_queues>`: either `queue1,queue2` (only those queues), `*` (all) or `-queue1,queue2` (all except those queues).
|
663
|
+
- `<participating_queues>`: either `queue1,queue2` (only those queues), `+queue1,queue2` (only those queues, and processed in order), `*` (all) or `-queue1,queue2` (all except those queues).
|
669
664
|
- `<thread_count>`: a count overriding for this specific pool the global `max-threads`.
|
670
665
|
|
671
666
|
Pool configurations are separated with a semicolon (;) in the `queues` configuration
|
@@ -683,6 +678,12 @@ By default, GoodJob creates a single thread execution pool that will execute job
|
|
683
678
|
- `-transactional_messages,batch_processing`: execute jobs enqueued on _any_ queue _excluding_ `transactional_messages` or `batch_processing`, with up to 2 threads.
|
684
679
|
- `*`: execute jobs on any queue, with up to 5 threads (as configured by `--max-threads=5`).
|
685
680
|
|
681
|
+
When a pool is performing jobs from multiple queues, jobs will be performed from specified queues, ordered by priority and creation time. To perform jobs from queues in the queues' given order, use the `+` modifier. In this example, jobs in `batch_processing` will be performed only when there are no jobs in `transactional_messages`:
|
682
|
+
|
683
|
+
```bash
|
684
|
+
bundle exec good_job --queues="+transactional_messages,batch_processing"
|
685
|
+
```
|
686
|
+
|
686
687
|
Configuration can be injected by environment variables too:
|
687
688
|
|
688
689
|
```bash
|
@@ -872,25 +873,24 @@ If your application is already using an ActiveJob backend, you will need to inst
|
|
872
873
|
|
873
874
|
GoodJob is fully instrumented with [`ActiveSupport::Notifications`](https://edgeguides.rubyonrails.org/active_support_instrumentation.html#introduction-to-instrumentation).
|
874
875
|
|
875
|
-
By default, GoodJob will preserve job records for 14 days after they are run, regardless of whether they succeed or
|
876
|
+
By default, GoodJob will preserve job records for 14 days after they are run, regardless of whether they succeed or raised an exception.
|
876
877
|
|
877
|
-
To
|
878
|
+
To instead delete job records immediately after they are finished:
|
878
879
|
|
879
880
|
```ruby
|
880
881
|
# config/initializers/good_job.rb
|
881
|
-
|
882
|
+
config.good_job.preserve_job_records = false # defaults to true; can also be `false` or `:on_unhandled_error`
|
882
883
|
```
|
883
884
|
|
884
|
-
GoodJob will automatically delete
|
885
|
+
GoodJob will automatically delete preserved job records after 14 days. The retention period, as well as the frequency GoodJob checks for deletable records can be configured:
|
885
886
|
|
886
887
|
```ruby
|
887
|
-
|
888
|
-
config.
|
889
|
-
config.
|
890
|
-
config.cleanup_interval_seconds = 10.minutes.to_i # Number of seconds between deletion sweeps.
|
888
|
+
config.good_job.cleanup_preserved_jobs_before_seconds_ago = 14.days.to_i
|
889
|
+
config.good_job.cleanup_interval_jobs = 1_000 # Number of executed jobs between deletion sweeps.
|
890
|
+
config.good_job.cleanup_interval_seconds = 10.minutes.to_i # Number of seconds between deletion sweeps.
|
891
891
|
```
|
892
892
|
|
893
|
-
It is also possible to manually trigger a cleanup:
|
893
|
+
It is also possible to manually trigger a cleanup of preserved job records:
|
894
894
|
|
895
895
|
- For example, in a Rake task:
|
896
896
|
|
@@ -1035,7 +1035,7 @@ For gem development and debugging information, please review the [README's Gem D
|
|
1035
1035
|
# Clone the repository locally
|
1036
1036
|
git clone git@github.com:bensheldon/good_job.git
|
1037
1037
|
|
1038
|
-
# Set up the
|
1038
|
+
# Set up the gem development environment
|
1039
1039
|
bin/setup
|
1040
1040
|
```
|
1041
1041
|
|
@@ -1074,6 +1074,10 @@ bundle install
|
|
1074
1074
|
Tests can be run against the primary development environment:
|
1075
1075
|
|
1076
1076
|
```bash
|
1077
|
+
# Set up the gem development environment
|
1078
|
+
bin/setup
|
1079
|
+
|
1080
|
+
# Run the tests
|
1077
1081
|
bin/rspec
|
1078
1082
|
```
|
1079
1083
|
|
@@ -4,11 +4,13 @@ import renderCharts from "charts";
|
|
4
4
|
import checkboxToggle from "checkbox_toggle";
|
5
5
|
import documentReady from "document_ready";
|
6
6
|
import showToasts from "toasts";
|
7
|
+
import setupPopovers from "popovers";
|
7
8
|
import LivePoll from "live_poll";
|
8
9
|
|
9
10
|
documentReady(function() {
|
10
11
|
renderCharts();
|
11
12
|
showToasts();
|
13
|
+
setupPopovers();
|
12
14
|
checkboxToggle();
|
13
15
|
|
14
16
|
const livePoll = new LivePoll
|
@@ -0,0 +1,7 @@
|
|
1
|
+
export default function() {
|
2
|
+
document.querySelectorAll('[data-bs-toggle="popover"]').forEach((el) => {
|
3
|
+
new bootstrap.Popover(el, {
|
4
|
+
template: '<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><pre class="popover-body text-wrap text-break"></pre></div>'
|
5
|
+
})
|
6
|
+
})
|
7
|
+
}
|
File without changes
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GoodJob
|
3
|
+
module Reportable
|
4
|
+
# There are 3 buckets of non-overlapping statuses:
|
5
|
+
# 1. The job will be executed
|
6
|
+
# - queued: The job will execute immediately when an execution thread becomes available.
|
7
|
+
# - scheduled: The job is scheduled to execute in the future.
|
8
|
+
# - retried: The job previously errored on execution and will be re-executed in the future.
|
9
|
+
# 2. The job is being executed
|
10
|
+
# - running: the job is actively being executed by an execution thread
|
11
|
+
# 3. The job will not execute
|
12
|
+
# - finished: The job executed successfully
|
13
|
+
# - discarded: The job previously errored on execution and will not be re-executed in the future.
|
14
|
+
#
|
15
|
+
# @return [Symbol]
|
16
|
+
def status
|
17
|
+
if finished_at.present?
|
18
|
+
if error.present? && retried_good_job_id.present?
|
19
|
+
:retried
|
20
|
+
elsif error.present? && retried_good_job_id.nil?
|
21
|
+
:discarded
|
22
|
+
else
|
23
|
+
:finished
|
24
|
+
end
|
25
|
+
elsif (scheduled_at || created_at) > DateTime.current
|
26
|
+
if serialized_params.fetch('executions', 0) > 1
|
27
|
+
:retried
|
28
|
+
else
|
29
|
+
:scheduled
|
30
|
+
end
|
31
|
+
elsif running?
|
32
|
+
:running
|
33
|
+
else
|
34
|
+
:queued
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# The last relevant timestamp for this execution
|
39
|
+
def last_status_at
|
40
|
+
finished_at || performed_at || scheduled_at || created_at
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
File without changes
|
File without changes
|
@@ -4,6 +4,7 @@ module GoodJob
|
|
4
4
|
class Execution < BaseRecord
|
5
5
|
include Lockable
|
6
6
|
include Filterable
|
7
|
+
include Reportable
|
7
8
|
|
8
9
|
# Raised if something attempts to execute a previously completed Execution again.
|
9
10
|
PreviouslyPerformedError = Class.new(StandardError)
|
@@ -29,15 +30,21 @@ module GoodJob
|
|
29
30
|
# not match.
|
30
31
|
# - +{ include: Array<String> }+ indicates the listed queue names should
|
31
32
|
# match.
|
33
|
+
# - +{ include: Array<String>, ordered_queues: true }+ indicates the listed
|
34
|
+
# queue names should match, and dequeue should respect queue order.
|
32
35
|
# @example
|
33
36
|
# GoodJob::Execution.queue_parser('-queue1,queue2')
|
34
37
|
# => { exclude: [ 'queue1', 'queue2' ] }
|
35
38
|
def self.queue_parser(string)
|
36
39
|
string = string.presence || '*'
|
37
40
|
|
38
|
-
|
41
|
+
case string.first
|
42
|
+
when '-'
|
39
43
|
exclude_queues = true
|
40
44
|
string = string[1..-1]
|
45
|
+
when '+'
|
46
|
+
ordered_queues = true
|
47
|
+
string = string[1..-1]
|
41
48
|
end
|
42
49
|
|
43
50
|
queues = string.split(',').map(&:strip)
|
@@ -46,6 +53,11 @@ module GoodJob
|
|
46
53
|
{ all: true }
|
47
54
|
elsif exclude_queues
|
48
55
|
{ exclude: queues }
|
56
|
+
elsif ordered_queues
|
57
|
+
{
|
58
|
+
include: queues,
|
59
|
+
ordered_queues: true,
|
60
|
+
}
|
49
61
|
else
|
50
62
|
{ include: queues }
|
51
63
|
end
|
@@ -95,10 +107,34 @@ module GoodJob
|
|
95
107
|
scope :creation_ordered, -> { order('created_at ASC') }
|
96
108
|
|
97
109
|
# Order jobs for de-queueing
|
98
|
-
# @!method
|
110
|
+
# @!method dequeueing_ordered
|
99
111
|
# @!scope class
|
100
|
-
# @
|
101
|
-
|
112
|
+
# @param parsed_queues [Hash]
|
113
|
+
# optional output of .queue_parser, parsed queues, will be used for
|
114
|
+
# ordered queues.
|
115
|
+
# @return [ActiveRecord::Relation]
|
116
|
+
scope :dequeueing_ordered, (lambda do |parsed_queues|
|
117
|
+
relation = self
|
118
|
+
relation = relation.queue_ordered(parsed_queues[:include]) if parsed_queues && parsed_queues[:ordered_queues] && parsed_queues[:include]
|
119
|
+
relation = relation.priority_ordered.creation_ordered
|
120
|
+
|
121
|
+
relation
|
122
|
+
end)
|
123
|
+
|
124
|
+
# Order jobs in order of queues in array param
|
125
|
+
# @!method queue_ordered
|
126
|
+
# @!scope class
|
127
|
+
# @param queues [Array<string] ordered names of queues
|
128
|
+
# @return [ActiveRecord::Relation]
|
129
|
+
scope :queue_ordered, (lambda do |queues|
|
130
|
+
clauses = queues.map.with_index do |queue_name, index|
|
131
|
+
"WHEN queue_name = '#{queue_name}' THEN #{index}"
|
132
|
+
end
|
133
|
+
|
134
|
+
order(
|
135
|
+
Arel.sql("(CASE #{clauses.join(' ')} ELSE #{queues.length} END)")
|
136
|
+
)
|
137
|
+
end)
|
102
138
|
|
103
139
|
# Order jobs by scheduled or created (oldest first).
|
104
140
|
# @!method schedule_ordered
|
@@ -165,8 +201,8 @@ module GoodJob
|
|
165
201
|
# return value for the job's +#perform+ method, and the exception the job
|
166
202
|
# raised, if any (if the job raised, then the second array entry will be
|
167
203
|
# +nil+). If there were no jobs to execute, returns +nil+.
|
168
|
-
def self.perform_with_advisory_lock
|
169
|
-
unfinished.
|
204
|
+
def self.perform_with_advisory_lock(parsed_queues: nil)
|
205
|
+
unfinished.dequeueing_ordered(parsed_queues).only_scheduled.limit(1).with_advisory_lock(unlock_session: true) do |executions|
|
170
206
|
execution = executions.first
|
171
207
|
break if execution.blank?
|
172
208
|
break :unlocked unless execution&.executable?
|
@@ -277,40 +313,6 @@ module GoodJob
|
|
277
313
|
end
|
278
314
|
end
|
279
315
|
|
280
|
-
# There are 3 buckets of non-overlapping statuses:
|
281
|
-
# 1. The job will be executed
|
282
|
-
# - queued: The job will execute immediately when an execution thread becomes available.
|
283
|
-
# - scheduled: The job is scheduled to execute in the future.
|
284
|
-
# - retried: The job previously errored on execution and will be re-executed in the future.
|
285
|
-
# 2. The job is being executed
|
286
|
-
# - running: the job is actively being executed by an execution thread
|
287
|
-
# 3. The job will not execute
|
288
|
-
# - finished: The job executed successfully
|
289
|
-
# - discarded: The job previously errored on execution and will not be re-executed in the future.
|
290
|
-
#
|
291
|
-
# @return [Symbol]
|
292
|
-
def status
|
293
|
-
if finished_at.present?
|
294
|
-
if error.present? && retried_good_job_id.present?
|
295
|
-
:retried
|
296
|
-
elsif error.present? && retried_good_job_id.nil?
|
297
|
-
:discarded
|
298
|
-
else
|
299
|
-
:finished
|
300
|
-
end
|
301
|
-
elsif (scheduled_at || created_at) > DateTime.current
|
302
|
-
if serialized_params.fetch('executions', 0) > 1
|
303
|
-
:retried
|
304
|
-
else
|
305
|
-
:scheduled
|
306
|
-
end
|
307
|
-
elsif running?
|
308
|
-
:running
|
309
|
-
else
|
310
|
-
:queued
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
316
|
# Return formatted serialized_params for display in the dashboard
|
315
317
|
# @return [Hash]
|
316
318
|
def display_serialized_params
|
@@ -331,11 +333,6 @@ module GoodJob
|
|
331
333
|
serialized_params.fetch('executions', 0) + 1
|
332
334
|
end
|
333
335
|
|
334
|
-
# The last relevant timestamp for this execution
|
335
|
-
def last_status_at
|
336
|
-
finished_at || performed_at || scheduled_at || created_at
|
337
|
-
end
|
338
|
-
|
339
336
|
# Time between when this job was expected to run and when it started running
|
340
337
|
def queue_latency
|
341
338
|
now = Time.zone.now
|
File without changes
|
@@ -8,6 +8,7 @@ module GoodJob
|
|
8
8
|
class Job < BaseRecord
|
9
9
|
include Filterable
|
10
10
|
include Lockable
|
11
|
+
include Reportable
|
11
12
|
|
12
13
|
# Raised when an inappropriate action is applied to a Job based on its state.
|
13
14
|
ActionForStateMismatchError = Class.new(StandardError)
|
@@ -27,7 +28,7 @@ module GoodJob
|
|
27
28
|
self.primary_key = 'active_job_id'
|
28
29
|
self.advisory_lockable_column = 'active_job_id'
|
29
30
|
|
30
|
-
has_many :executions, -> { order(created_at: :asc) }, class_name: 'GoodJob::Execution', foreign_key: 'active_job_id', inverse_of: :job
|
31
|
+
has_many :executions, -> { order(created_at: :asc) }, class_name: 'GoodJob::Execution', foreign_key: 'active_job_id', inverse_of: :job # rubocop:disable Rails/HasManyOrHasOneDependent
|
31
32
|
|
32
33
|
# Only the most-recent unretried execution represents a "Job"
|
33
34
|
default_scope { where(retried_good_job_id: nil) }
|
@@ -73,32 +74,6 @@ module GoodJob
|
|
73
74
|
serialized_params['job_class']
|
74
75
|
end
|
75
76
|
|
76
|
-
def last_status_at
|
77
|
-
finished_at || performed_at || scheduled_at || created_at
|
78
|
-
end
|
79
|
-
|
80
|
-
def status
|
81
|
-
if finished_at.present?
|
82
|
-
if error.present? && retried_good_job_id.present?
|
83
|
-
:retried
|
84
|
-
elsif error.present? && retried_good_job_id.nil?
|
85
|
-
:discarded
|
86
|
-
else
|
87
|
-
:finished
|
88
|
-
end
|
89
|
-
elsif (scheduled_at || created_at) > DateTime.current
|
90
|
-
if serialized_params.fetch('executions', 0) > 1
|
91
|
-
:retried
|
92
|
-
else
|
93
|
-
:scheduled
|
94
|
-
end
|
95
|
-
elsif running?
|
96
|
-
:running
|
97
|
-
else
|
98
|
-
:queued
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
77
|
# Override #reload to add a custom scope to ensure the reloaded record is the head execution
|
103
78
|
# @return [Job]
|
104
79
|
def reload(options = nil)
|
File without changes
|