good_job 2.17.1 → 3.0.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 +44 -1
- data/README.md +45 -26
- data/app/charts/good_job/scheduled_by_queue_chart.rb +1 -1
- data/app/controllers/good_job/jobs_controller.rb +11 -11
- data/app/controllers/good_job/processes_controller.rb +1 -1
- data/app/filters/good_job/jobs_filter.rb +2 -2
- data/app/views/good_job/processes/index.html.erb +1 -9
- data/app/views/layouts/good_job/application.html.erb +1 -1
- data/lib/generators/good_job/templates/update/migrations/01_create_good_jobs.rb.erb +9 -0
- data/lib/good_job/adapter.rb +6 -49
- data/lib/good_job/configuration.rb +4 -4
- data/lib/good_job/current_thread.rb +2 -2
- data/lib/good_job/notifier/process_registration.rb +0 -4
- data/lib/good_job/version.rb +1 -1
- data/lib/good_job.rb +7 -9
- data/lib/models/good_job/active_job_job.rb +6 -219
- data/lib/{good_job → models/good_job}/cron_entry.rb +3 -3
- data/lib/models/good_job/execution.rb +3 -11
- data/lib/models/good_job/job.rb +224 -0
- data/lib/{good_job → models/good_job}/lockable.rb +0 -0
- data/lib/models/good_job/process.rb +0 -9
- metadata +23 -27
- data/lib/generators/good_job/templates/update/migrations/02_add_cron_at_to_good_jobs.rb.erb +0 -14
- data/lib/generators/good_job/templates/update/migrations/03_add_cron_key_cron_at_index_to_good_jobs.rb.erb +0 -20
- data/lib/generators/good_job/templates/update/migrations/04_create_good_job_processes.rb.erb +0 -17
- data/lib/generators/good_job/templates/update/migrations/04_index_good_job_jobs_on_finished_at.rb.erb +0 -25
- data/lib/good_job/job.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 381f27d5c5f8fe4be355f3b2ea1e1f0bcd76f545d7378183b4faca9d6770a6cd
|
4
|
+
data.tar.gz: 20b315936f49810e9aa70e0bc8c2a37c140436212f2e84d15e05d275c93715ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0f107ba18b85211856391873650309997a63e16d2ddc34e55bdbdb3f8563e595f2e3176cfaa1e13f65eaca70e75df0ff950562740d51c1a82bc885dfd3421ea
|
7
|
+
data.tar.gz: cc47bc865ca1264238b5253f9ab06c8ebdc840e5adaf3220366f622626f8fac872c5fec5cd3b939acfd60137af6d984a0b2a61aad19ccd3ea277708f3c291414
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,49 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v3.0.1](https://github.com/bensheldon/good_job/tree/v3.0.1) (2022-07-02)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.0.0...v3.0.1)
|
6
|
+
|
7
|
+
**Closed issues:**
|
8
|
+
|
9
|
+
- ERROR: relation "good\_jobs" does not exist at character 454 [\#308](https://github.com/bensheldon/good_job/issues/308)
|
10
|
+
|
11
|
+
**Merged pull requests:**
|
12
|
+
|
13
|
+
- 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))
|
14
|
+
- Create codeql-analysis.yml [\#648](https://github.com/bensheldon/good_job/pull/648) ([bensheldon](https://github.com/bensheldon))
|
15
|
+
|
16
|
+
## [v3.0.0](https://github.com/bensheldon/good_job/tree/v3.0.0) (2022-06-26)
|
17
|
+
|
18
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v2.99.0...v3.0.0)
|
19
|
+
|
20
|
+
**Implemented enhancements:**
|
21
|
+
|
22
|
+
- By default, preserve job records and automatically them clean up [\#545](https://github.com/bensheldon/good_job/pull/545) ([bensheldon](https://github.com/bensheldon))
|
23
|
+
|
24
|
+
**Merged pull requests:**
|
25
|
+
|
26
|
+
- Update tests to reflect default of `GoodJob.preserve_job_records = true`; update appraisal Gemfiles too [\#643](https://github.com/bensheldon/good_job/pull/643) ([bensheldon](https://github.com/bensheldon))
|
27
|
+
- Remove database migration shims and old migrations [\#642](https://github.com/bensheldon/good_job/pull/642) ([bensheldon](https://github.com/bensheldon))
|
28
|
+
- Remove support for EOL Rails 5.2 [\#637](https://github.com/bensheldon/good_job/pull/637) ([bensheldon](https://github.com/bensheldon))
|
29
|
+
- Remove/rename deprecated behavior and constants for GoodJob v3 [\#633](https://github.com/bensheldon/good_job/pull/633) ([bensheldon](https://github.com/bensheldon))
|
30
|
+
|
31
|
+
## [v2.99.0](https://github.com/bensheldon/good_job/tree/v2.99.0) (2022-06-26)
|
32
|
+
|
33
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v2.17.1...v2.99.0)
|
34
|
+
|
35
|
+
**Closed issues:**
|
36
|
+
|
37
|
+
- How to accomplish user controlled recurring jobs? [\#640](https://github.com/bensheldon/good_job/issues/640)
|
38
|
+
- "uninitialized constant GoodJob::Execution" in development env [\#634](https://github.com/bensheldon/good_job/issues/634)
|
39
|
+
|
40
|
+
**Merged pull requests:**
|
41
|
+
|
42
|
+
- Create upgrade instructions for v2.99 -\> v3.0.0 [\#641](https://github.com/bensheldon/good_job/pull/641) ([bensheldon](https://github.com/bensheldon))
|
43
|
+
- Update development dependencies; delete Gemfile.lock in CI to avoid Ruby version dependency mismatches [\#639](https://github.com/bensheldon/good_job/pull/639) ([bensheldon](https://github.com/bensheldon))
|
44
|
+
- Put more model files in `lib/models` and align specs too [\#638](https://github.com/bensheldon/good_job/pull/638) ([bensheldon](https://github.com/bensheldon))
|
45
|
+
- Generate sha256 checksums on gem release too [\#636](https://github.com/bensheldon/good_job/pull/636) ([bensheldon](https://github.com/bensheldon))
|
46
|
+
|
3
47
|
## [v2.17.1](https://github.com/bensheldon/good_job/tree/v2.17.1) (2022-06-24)
|
4
48
|
|
5
49
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v2.17.0...v2.17.1)
|
@@ -980,7 +1024,6 @@
|
|
980
1024
|
|
981
1025
|
**Closed issues:**
|
982
1026
|
|
983
|
-
- ERROR: relation "good\_jobs" does not exist at character 454 [\#308](https://github.com/bensheldon/good_job/issues/308)
|
984
1027
|
- Add Frozen String Literal to all files [\#298](https://github.com/bensheldon/good_job/issues/298)
|
985
1028
|
- Support for good\_job without Rails? [\#295](https://github.com/bensheldon/good_job/issues/295)
|
986
1029
|
|
data/README.md
CHANGED
@@ -46,6 +46,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
46
46
|
- [Cron-style repeating/recurring jobs](#cron-style-repeatingrecurring-jobs)
|
47
47
|
- [Updating](#updating)
|
48
48
|
- [Upgrading minor versions](#upgrading-minor-versions)
|
49
|
+
- [Upgrading v2 to v3](#upgrading-v2-to-v3)
|
49
50
|
- [Upgrading v1 to v2](#upgrading-v1-to-v2)
|
50
51
|
- [Go deeper](#go-deeper)
|
51
52
|
- [Exceptions, retries, and reliability](#exceptions-retries-and-reliability)
|
@@ -143,9 +144,9 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
143
144
|
|
144
145
|
## Compatibility
|
145
146
|
|
146
|
-
- **Ruby on Rails:**
|
147
|
-
- **Ruby:**
|
148
|
-
- **Postgres:**
|
147
|
+
- **Ruby on Rails:** 6.0+
|
148
|
+
- **Ruby:** Ruby 2.5+. JRuby 9.2.13+
|
149
|
+
- **Postgres:** 10.0+
|
149
150
|
|
150
151
|
## Configuration
|
151
152
|
|
@@ -279,7 +280,7 @@ Available configuration options are:
|
|
279
280
|
- `cleanup_interval_seconds` (integer) Number of seconds a Scheduler will wait before cleaning up preserved jobs. Defaults to `nil`. Can also be set with the environment variable `GOOD_JOB_CLEANUP_INTERVAL_SECONDS`.
|
280
281
|
- `inline_execution_respects_schedule` (boolean) Opt-in to future behavior of inline execution respecting scheduled jobs. Defaults to `false`.
|
281
282
|
- `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`).
|
282
|
-
- `preserve_job_records` (boolean) keeps job records in your database even after jobs are completed. (Default: `
|
283
|
+
- `preserve_job_records` (boolean) keeps job records in your database even after jobs are completed. (Default: `true`)
|
283
284
|
- `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: `true`)
|
284
285
|
- `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. Example:
|
285
286
|
|
@@ -310,8 +311,8 @@ Good Job’s general behavior can also be configured via attributes directly on
|
|
310
311
|
|
311
312
|
- **`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._
|
312
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`.
|
313
|
-
- **`GoodJob.preserve_job_records`** (boolean) keeps job records in your database even after jobs are completed. (Default: `
|
314
|
-
- **`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: `
|
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`)
|
315
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.
|
316
317
|
|
317
318
|
You’ll generally want to configure these in `config/initializers/good_job.rb`, like so:
|
@@ -394,8 +395,6 @@ The Dashboard can be set to automatically refresh by checking "Live Poll" in the
|
|
394
395
|
|
395
396
|
GoodJob can extend ActiveJob to provide limits on concurrently running jobs, either at time of _enqueue_ or at _perform_. Limiting concurrency can help prevent duplicate, double or unecessary jobs from being enqueued, or race conditions when performing, for example when interacting with 3rd-party APIs.
|
396
397
|
|
397
|
-
**Note:** Limiting concurrency at _enqueue_ requires Rails 6.0+ because Rails 5.2 cannot halt ActiveJob callbacks.
|
398
|
-
|
399
398
|
```ruby
|
400
399
|
class MyJob < ApplicationJob
|
401
400
|
include GoodJob::ActiveJobExtensions::Concurrency
|
@@ -509,9 +508,25 @@ To perform upgrades to the GoodJob database tables:
|
|
509
508
|
1. Commit the migration files and resulting `db/schema.rb` changes.
|
510
509
|
1. Deploy the code, run the migrations against the production database, and restart server/worker processes.
|
511
510
|
|
511
|
+
#### Upgrading v2 to v3
|
512
|
+
|
513
|
+
GoodJob v3 is operationally identical to v2; upgrading to GoodJob v3 should be simple. If you are already using `>= v2.9+` no other changes are necessary.
|
514
|
+
|
515
|
+
1. Upgrade to `v2.99.x`, following the minor version upgrade process, running any remaining database migrations (`rails g good_job:update`) and addressing deprecation warnings.
|
516
|
+
1. Upgrade from `v2.99.x` to `v3.x`
|
517
|
+
|
518
|
+
Notable changes:
|
519
|
+
|
520
|
+
- Defaults to preserve job records, and automatically delete them after 14 days.
|
521
|
+
- Defaults to discarding failed jobs, instead of immediately retrying them.
|
522
|
+
- `:inline` execution mode respects job schedules. Tests can invoke `GoodJob.perform_inline` to execute jobs.
|
523
|
+
- `GoodJob::Adapter` can no longer can be initialized with custom execution options (`queues:`, `max_threads:`, `poll_interval:`).
|
524
|
+
- Renames `GoodJob::ActiveJobJob` to `GoodJob::Job`.
|
525
|
+
- Removes support for Rails 5.2.
|
526
|
+
|
512
527
|
#### Upgrading v1 to v2
|
513
528
|
|
514
|
-
GoodJob v2 introduces a new Advisory Lock key format that is different than the v1 advisory lock key format; it's therefore necessary to perform a simple, but staged production upgrade. If you are already using `>= v1.12+` no other changes are necessary.
|
529
|
+
GoodJob v2 introduces a new Advisory Lock key format that is operationally different than the v1 advisory lock key format; it's therefore necessary to perform a simple, but staged production upgrade. If you are already using `>= v1.12+` no other changes are necessary.
|
515
530
|
|
516
531
|
1. Upgrade your production environment to `v1.99.x` following the minor version upgrade process, including database migrations. `v1.99` is a transitional release that is safely compatible with both `v1.x` and `v2.0.0` because it uses both `v1`- and `v2`-formatted advisory locks.
|
517
532
|
1. Address any deprecation warnings generated by `v1.99`.
|
@@ -547,9 +562,9 @@ GoodJob.on_thread_error = -> (exception) { Raven.capture_exception(exception) }
|
|
547
562
|
|
548
563
|
#### Retries
|
549
564
|
|
550
|
-
By default, GoodJob
|
565
|
+
By default, GoodJob relies on ActiveJob's retry functionality.
|
551
566
|
|
552
|
-
|
567
|
+
ActiveJob can be configured to retry an infinite number of times, with an exponential backoff. Using ActiveJob's `retry_on` prevents exceptions from reaching GoodJob:
|
553
568
|
|
554
569
|
```ruby
|
555
570
|
class ApplicationJob < ActiveJob::Base
|
@@ -558,14 +573,7 @@ class ApplicationJob < ActiveJob::Base
|
|
558
573
|
end
|
559
574
|
```
|
560
575
|
|
561
|
-
When using `retry_on` with _a limited number of retries_, the final exception will not be rescued and will raise to GoodJob
|
562
|
-
|
563
|
-
```ruby
|
564
|
-
# config/initializers/good_job.rb
|
565
|
-
GoodJob.retry_on_unhandled_error = false
|
566
|
-
```
|
567
|
-
|
568
|
-
Alternatively, pass a block to `retry_on` to handle the final exception instead of raising it to GoodJob:
|
576
|
+
When using `retry_on` with _a limited number of retries_, the final exception will not be rescued and will raise to GoodJob's error handler. To avoid this, pass a block to `retry_on` to handle the final exception instead of raising it to GoodJob:
|
569
577
|
|
570
578
|
```ruby
|
571
579
|
class ApplicationJob < ActiveJob::Base
|
@@ -596,9 +604,11 @@ class ApplicationJob < ActiveJob::Base
|
|
596
604
|
end
|
597
605
|
```
|
598
606
|
|
607
|
+
By default, jobs will not be retried unless `retry_on` is configured. This can be overridden by setting `GoodJob.retry_on_unhandled_error` to `true`; GoodJob will then retry the failing job immediately and infinitely, potentially causing high load.
|
608
|
+
|
599
609
|
#### ActionMailer retries
|
600
610
|
|
601
|
-
Any configuration in `ApplicationJob` will have to be duplicated on `ActionMailer::MailDeliveryJob`
|
611
|
+
Any configuration in `ApplicationJob` will have to be duplicated on `ActionMailer::MailDeliveryJob` because ActionMailer uses that custom class which inherits from `ActiveJob::Base`, rather than your application's `ApplicationJob`.
|
602
612
|
|
603
613
|
You can use an initializer to configure `ActionMailer::MailDeliveryJob`, for example:
|
604
614
|
|
@@ -852,22 +862,31 @@ If your application is already using an ActiveJob backend, you will need to inst
|
|
852
862
|
|
853
863
|
GoodJob is fully instrumented with [`ActiveSupport::Notifications`](https://edgeguides.rubyonrails.org/active_support_instrumentation.html#introduction-to-instrumentation).
|
854
864
|
|
855
|
-
By default, GoodJob will
|
865
|
+
By default, GoodJob will preserve job records for 14 days after they are run, regardless of whether they succeed or not (raising a kind of `StandardError`), unless they are interrupted (raising a kind of `Exception`).
|
856
866
|
|
857
|
-
To preserve job records for later inspection, set an initializer:
|
867
|
+
To not preserve job records for later inspection, set an initializer:
|
858
868
|
|
859
869
|
```ruby
|
860
870
|
# config/initializers/good_job.rb
|
861
|
-
GoodJob.preserve_job_records = true
|
871
|
+
GoodJob.preserve_job_records = false # defaults to true, or `false` or `:on_unhandled_error`
|
872
|
+
```
|
873
|
+
|
874
|
+
GoodJob will automatically delete these job records after 14 days. The retention period, as well as the frequency GoodJob checks for deletable records can be configured:
|
875
|
+
|
876
|
+
```ruby
|
877
|
+
|
878
|
+
config.cleanup_preserved_jobs_before_seconds_ago = 14.days.to_i
|
879
|
+
config.cleanup_interval_jobs = 1_000 # Number of executed jobs between deletion sweeps.
|
880
|
+
config.cleanup_interval_seconds = 10.minutes.to_i # Number of seconds between deletion sweeps.
|
862
881
|
```
|
863
882
|
|
864
|
-
It is also
|
883
|
+
It is also possible to manually trigger a cleanup:
|
865
884
|
|
866
885
|
- For example, in a Rake task:
|
867
886
|
|
868
887
|
```ruby
|
869
|
-
GoodJob.cleanup_preserved_jobs # Will
|
870
|
-
GoodJob.cleanup_preserved_jobs(older_than: 7.days) #
|
888
|
+
GoodJob.cleanup_preserved_jobs # Will use default retention period
|
889
|
+
GoodJob.cleanup_preserved_jobs(older_than: 7.days) # custom retention period
|
871
890
|
```
|
872
891
|
|
873
892
|
- For example, using the `good_job` command-line utility:
|
@@ -9,7 +9,7 @@ module GoodJob
|
|
9
9
|
def data
|
10
10
|
end_time = Time.current
|
11
11
|
start_time = end_time - 1.day
|
12
|
-
table_name = GoodJob::
|
12
|
+
table_name = GoodJob::Job.table_name
|
13
13
|
|
14
14
|
count_query = Arel.sql(GoodJob::Execution.pg_or_jdbc_query(<<~SQL.squish))
|
15
15
|
SELECT *
|
@@ -10,8 +10,8 @@ module GoodJob
|
|
10
10
|
destroy: "destroyed",
|
11
11
|
}.freeze
|
12
12
|
|
13
|
-
rescue_from GoodJob::
|
14
|
-
GoodJob::
|
13
|
+
rescue_from GoodJob::Job::AdapterNotGoodJobError,
|
14
|
+
GoodJob::Job::ActionForStateMismatchError,
|
15
15
|
with: :redirect_on_error
|
16
16
|
|
17
17
|
def index
|
@@ -26,7 +26,7 @@ module GoodJob
|
|
26
26
|
JobsFilter.new(params).filtered_query
|
27
27
|
else
|
28
28
|
job_ids = params.fetch(:job_ids, [])
|
29
|
-
|
29
|
+
Job.where(active_job_id: job_ids)
|
30
30
|
end
|
31
31
|
|
32
32
|
processed_jobs = jobs.map do |job|
|
@@ -42,7 +42,7 @@ module GoodJob
|
|
42
42
|
end
|
43
43
|
|
44
44
|
job
|
45
|
-
rescue GoodJob::
|
45
|
+
rescue GoodJob::Job::ActionForStateMismatchError
|
46
46
|
nil
|
47
47
|
end.compact
|
48
48
|
|
@@ -56,29 +56,29 @@ module GoodJob
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def show
|
59
|
-
@job =
|
59
|
+
@job = Job.find(params[:id])
|
60
60
|
end
|
61
61
|
|
62
62
|
def discard
|
63
|
-
@job =
|
63
|
+
@job = Job.find(params[:id])
|
64
64
|
@job.discard_job(DISCARD_MESSAGE)
|
65
65
|
redirect_back(fallback_location: jobs_path, notice: "Job has been discarded")
|
66
66
|
end
|
67
67
|
|
68
68
|
def reschedule
|
69
|
-
@job =
|
69
|
+
@job = Job.find(params[:id])
|
70
70
|
@job.reschedule_job
|
71
71
|
redirect_back(fallback_location: jobs_path, notice: "Job has been rescheduled")
|
72
72
|
end
|
73
73
|
|
74
74
|
def retry
|
75
|
-
@job =
|
75
|
+
@job = Job.find(params[:id])
|
76
76
|
@job.retry_job
|
77
77
|
redirect_back(fallback_location: jobs_path, notice: "Job has been retried")
|
78
78
|
end
|
79
79
|
|
80
80
|
def destroy
|
81
|
-
@job =
|
81
|
+
@job = Job.find(params[:id])
|
82
82
|
@job.destroy_job
|
83
83
|
redirect_back(fallback_location: jobs_path, notice: "Job has been destroyed")
|
84
84
|
end
|
@@ -87,9 +87,9 @@ module GoodJob
|
|
87
87
|
|
88
88
|
def redirect_on_error(exception)
|
89
89
|
alert = case exception
|
90
|
-
when GoodJob::
|
90
|
+
when GoodJob::Job::AdapterNotGoodJobError
|
91
91
|
"ActiveJob Queue Adapter must be GoodJob."
|
92
|
-
when GoodJob::
|
92
|
+
when GoodJob::Job::ActionForStateMismatchError
|
93
93
|
"Job is not in an appropriate state for this action."
|
94
94
|
else
|
95
95
|
exception.to_s
|
@@ -31,7 +31,7 @@ module GoodJob
|
|
31
31
|
when 'scheduled'
|
32
32
|
query = query.scheduled
|
33
33
|
when 'running'
|
34
|
-
query = query.running.select("#{GoodJob::
|
34
|
+
query = query.running.select("#{GoodJob::Job.table_name}.*", 'pg_locks.locktype')
|
35
35
|
when 'queued'
|
36
36
|
query = query.queued
|
37
37
|
end
|
@@ -47,7 +47,7 @@ module GoodJob
|
|
47
47
|
private
|
48
48
|
|
49
49
|
def default_base_query
|
50
|
-
GoodJob::
|
50
|
+
GoodJob::Job.all
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -3,15 +3,7 @@
|
|
3
3
|
</div>
|
4
4
|
|
5
5
|
<div data-live-poll-region="processes">
|
6
|
-
<% if
|
7
|
-
<div class="card my-3">
|
8
|
-
<div class="card-body">
|
9
|
-
<p class="card-text">
|
10
|
-
<em>Feature unavailable because of pending database migration.</em>
|
11
|
-
</p>
|
12
|
-
</div>
|
13
|
-
</div>
|
14
|
-
<% elsif @processes.present? %>
|
6
|
+
<% if @processes.present? %>
|
15
7
|
<div class="card my-3">
|
16
8
|
<div class="table-responsive">
|
17
9
|
<table class="table card-table table-bordered table-hover table-sm mb-0">
|
@@ -16,7 +16,7 @@
|
|
16
16
|
<%= tag.script "", src: rails_ujs_path(format: :js, v: GoodJob::VERSION, locale: nil), nonce: content_security_policy_nonce %>
|
17
17
|
|
18
18
|
<%= tag.script "", src: es_module_shims_path(format: :js, v: GoodJob::VERSION, locale: nil), async: true, nonce: content_security_policy_nonce %>
|
19
|
-
<% importmaps = { imports: GoodJob::AssetsController.js_modules.keys.
|
19
|
+
<% importmaps = { imports: GoodJob::AssetsController.js_modules.keys.index_with { |module_name| modules_path(module_name, format: :js, locale: nil, v: GoodJob::VERSION) } } %>
|
20
20
|
<%= tag.script importmaps.to_json.html_safe, type: "importmap", nonce: content_security_policy_nonce %>
|
21
21
|
<%= tag.script "", src: scripts_path(format: :js, v: GoodJob::VERSION, locale: nil), type: "module", nonce: content_security_policy_nonce %>
|
22
22
|
</head>
|
@@ -18,6 +18,12 @@ class CreateGoodJobs < ActiveRecord::Migration<%= migration_version %>
|
|
18
18
|
t.text :concurrency_key
|
19
19
|
t.text :cron_key
|
20
20
|
t.uuid :retried_good_job_id
|
21
|
+
t.timestamp :cron_at
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table :good_job_processes, id: :uuid do |t|
|
25
|
+
t.timestamps
|
26
|
+
t.jsonb :state
|
21
27
|
end
|
22
28
|
|
23
29
|
add_index :good_jobs, :scheduled_at, where: "(finished_at IS NULL)", name: "index_good_jobs_on_scheduled_at"
|
@@ -25,5 +31,8 @@ class CreateGoodJobs < ActiveRecord::Migration<%= migration_version %>
|
|
25
31
|
add_index :good_jobs, [:active_job_id, :created_at], name: :index_good_jobs_on_active_job_id_and_created_at
|
26
32
|
add_index :good_jobs, :concurrency_key, where: "(finished_at IS NULL)", name: :index_good_jobs_on_concurrency_key_when_unfinished
|
27
33
|
add_index :good_jobs, [:cron_key, :created_at], name: :index_good_jobs_on_cron_key_and_created_at
|
34
|
+
add_index :good_jobs, [:cron_key, :cron_at], name: :index_good_jobs_on_cron_key_and_cron_at, unique: true
|
35
|
+
add_index :good_jobs, [:active_job_id], name: :index_good_jobs_on_active_job_id
|
36
|
+
add_index :good_jobs, [:finished_at], where: "retried_good_job_id IS NULL AND finished_at IS NOT NULL", name: :index_good_jobs_jobs_on_finished_at
|
28
37
|
end
|
29
38
|
end
|
data/lib/good_job/adapter.rb
CHANGED
@@ -20,32 +20,16 @@ module GoodJob
|
|
20
20
|
#
|
21
21
|
# The default value depends on the Rails environment:
|
22
22
|
#
|
23
|
-
# - +development
|
23
|
+
# - +development+: +:async:+
|
24
|
+
# -+test+: +:inline+
|
24
25
|
# - +production+ and all other environments: +:external+
|
25
26
|
#
|
26
|
-
|
27
|
-
|
28
|
-
# @param poll_interval [Integer, nil] sets the number of seconds between polls for jobs when +execution_mode+ is set to +:async+. You can also set this with the environment variable +GOOD_JOB_POLL_INTERVAL+. Defaults to +1+.
|
29
|
-
# @param start_async_on_initialize [Boolean] whether to start the async scheduler when the adapter is initialized.
|
30
|
-
def initialize(execution_mode: nil, queues: nil, max_threads: nil, poll_interval: nil, start_async_on_initialize: nil)
|
31
|
-
if queues || max_threads || poll_interval || start_async_on_initialize
|
32
|
-
ActiveSupport::Deprecation.warn(
|
33
|
-
"GoodJob::Adapter's execution-related arguments (queues, max_threads, poll_interval, start_async_on_initialize) have been deprecated and will be removed in GoodJob v3. These options should be configured through GoodJob global configuration instead."
|
34
|
-
)
|
35
|
-
end
|
36
|
-
|
37
|
-
@configuration = GoodJob::Configuration.new(
|
38
|
-
{
|
39
|
-
execution_mode: execution_mode,
|
40
|
-
queues: queues,
|
41
|
-
max_threads: max_threads,
|
42
|
-
poll_interval: poll_interval,
|
43
|
-
}
|
44
|
-
)
|
27
|
+
def initialize(execution_mode: nil)
|
28
|
+
@configuration = GoodJob::Configuration.new({ execution_mode: execution_mode })
|
45
29
|
@configuration.validate!
|
46
30
|
self.class.instances << self
|
47
31
|
|
48
|
-
start_async if
|
32
|
+
start_async if GoodJob.async_ready?
|
49
33
|
end
|
50
34
|
|
51
35
|
# Enqueues the ActiveJob job to be performed.
|
@@ -63,11 +47,7 @@ module GoodJob
|
|
63
47
|
# @return [GoodJob::Execution]
|
64
48
|
def enqueue_at(active_job, timestamp)
|
65
49
|
scheduled_at = timestamp ? Time.zone.at(timestamp) : nil
|
66
|
-
|
67
|
-
if execute_inline?
|
68
|
-
future_scheduled = scheduled_at && scheduled_at > Time.current
|
69
|
-
will_execute_inline = !future_scheduled || (future_scheduled && !@configuration.inline_execution_respects_schedule?)
|
70
|
-
end
|
50
|
+
will_execute_inline = execute_inline? && (scheduled_at.nil? || scheduled_at <= Time.current)
|
71
51
|
|
72
52
|
execution = GoodJob::Execution.enqueue(
|
73
53
|
active_job,
|
@@ -76,29 +56,6 @@ module GoodJob
|
|
76
56
|
)
|
77
57
|
|
78
58
|
if will_execute_inline
|
79
|
-
if future_scheduled && !@configuration.inline_execution_respects_schedule?
|
80
|
-
ActiveSupport::Deprecation.warn(<<~DEPRECATION)
|
81
|
-
In the next major release, GoodJob will not *inline* execute
|
82
|
-
future-scheduled jobs.
|
83
|
-
|
84
|
-
To opt into this behavior immediately set:
|
85
|
-
`config.good_job.inline_execution_respects_schedule = true`
|
86
|
-
|
87
|
-
To perform jobs inline at any time, use `GoodJob.perform_inline`.
|
88
|
-
|
89
|
-
For example, using time helpers within an integration test:
|
90
|
-
|
91
|
-
```
|
92
|
-
MyJob.set(wait: 10.minutes).perform_later
|
93
|
-
travel_to(15.minutes.from_now) { GoodJob.perform_inline }
|
94
|
-
```
|
95
|
-
|
96
|
-
Note: Rails `travel`/`travel_to` time helpers do not have millisecond
|
97
|
-
precision, so you must leave at least 1 second between the schedule
|
98
|
-
and time traveling for the job to be executed.
|
99
|
-
DEPRECATION
|
100
|
-
end
|
101
|
-
|
102
59
|
begin
|
103
60
|
result = execution.perform
|
104
61
|
ensure
|
@@ -15,13 +15,13 @@ module GoodJob
|
|
15
15
|
# Default poll interval for async in development environment
|
16
16
|
DEFAULT_DEVELOPMENT_ASYNC_POLL_INTERVAL = -1
|
17
17
|
# Default number of threads to use per {Scheduler}
|
18
|
-
DEFAULT_MAX_CACHE =
|
18
|
+
DEFAULT_MAX_CACHE = 10_000
|
19
19
|
# Default number of seconds to preserve jobs for {CLI#cleanup_preserved_jobs} and {GoodJob.cleanup_preserved_jobs}
|
20
|
-
DEFAULT_CLEANUP_PRESERVED_JOBS_BEFORE_SECONDS_AGO =
|
20
|
+
DEFAULT_CLEANUP_PRESERVED_JOBS_BEFORE_SECONDS_AGO = 14.days.to_i
|
21
21
|
# Default number of jobs to execute between preserved job cleanup runs
|
22
|
-
DEFAULT_CLEANUP_INTERVAL_JOBS =
|
22
|
+
DEFAULT_CLEANUP_INTERVAL_JOBS = 1_000
|
23
23
|
# Default number of seconds to wait between preserved job cleanup runs
|
24
|
-
DEFAULT_CLEANUP_INTERVAL_SECONDS =
|
24
|
+
DEFAULT_CLEANUP_INTERVAL_SECONDS = 10.minutes.to_i
|
25
25
|
# Default to always wait for jobs to finish for {Adapter#shutdown}
|
26
26
|
DEFAULT_SHUTDOWN_TIMEOUT = -1
|
27
27
|
# Default to not running cron
|
@@ -14,8 +14,6 @@ module GoodJob # :nodoc:
|
|
14
14
|
# Registers the current process.
|
15
15
|
def register_process
|
16
16
|
GoodJob::Process.with_connection(connection) do
|
17
|
-
next unless Process.migrated?
|
18
|
-
|
19
17
|
GoodJob::Process.cleanup
|
20
18
|
@process = GoodJob::Process.register
|
21
19
|
end
|
@@ -24,8 +22,6 @@ module GoodJob # :nodoc:
|
|
24
22
|
# Deregisters the current process.
|
25
23
|
def deregister_process
|
26
24
|
GoodJob::Process.with_connection(connection) do
|
27
|
-
next unless Process.migrated?
|
28
|
-
|
29
25
|
@process&.deregister
|
30
26
|
end
|
31
27
|
end
|
data/lib/good_job/version.rb
CHANGED
data/lib/good_job.rb
CHANGED
@@ -43,23 +43,21 @@ module GoodJob
|
|
43
43
|
|
44
44
|
# @!attribute [rw] preserve_job_records
|
45
45
|
# @!scope class
|
46
|
-
# Whether to preserve job records in the database after they have finished (default: +
|
47
|
-
# By default, GoodJob
|
46
|
+
# Whether to preserve job records in the database after they have finished (default: +true+).
|
47
|
+
# By default, GoodJob deletes job records after the job is completed successfully.
|
48
48
|
# If you want to preserve jobs for latter inspection, set this to +true+.
|
49
49
|
# If you want to preserve only jobs that finished with error for latter inspection, set this to +:on_unhandled_error+.
|
50
|
-
# If +true+, you will need to clean out jobs using the +good_job cleanup_preserved_jobs+ CLI command or
|
51
|
-
# by using +Goodjob.cleanup_preserved_jobs+.
|
52
50
|
# @return [Boolean, nil]
|
53
|
-
mattr_accessor :preserve_job_records, default:
|
51
|
+
mattr_accessor :preserve_job_records, default: true
|
54
52
|
|
55
53
|
# @!attribute [rw] retry_on_unhandled_error
|
56
54
|
# @!scope class
|
57
|
-
# Whether to re-perform a job when a type of +StandardError+ is raised to GoodJob (default: +
|
55
|
+
# Whether to re-perform a job when a type of +StandardError+ is raised to GoodJob (default: +false+).
|
58
56
|
# If +true+, causes jobs to be re-queued and retried if they raise an instance of +StandardError+.
|
59
57
|
# If +false+, jobs will be discarded or marked as finished if they raise an instance of +StandardError+.
|
60
58
|
# Instances of +Exception+, like +SIGINT+, will *always* be retried, regardless of this attribute's value.
|
61
59
|
# @return [Boolean, nil]
|
62
|
-
mattr_accessor :retry_on_unhandled_error, default:
|
60
|
+
mattr_accessor :retry_on_unhandled_error, default: false
|
63
61
|
|
64
62
|
# @!attribute [rw] on_thread_error
|
65
63
|
# @!scope class
|
@@ -143,11 +141,11 @@ module GoodJob
|
|
143
141
|
include_discarded = configuration.cleanup_discarded_jobs?
|
144
142
|
|
145
143
|
ActiveSupport::Notifications.instrument("cleanup_preserved_jobs.good_job", { older_than: older_than, timestamp: timestamp }) do |payload|
|
146
|
-
old_jobs = GoodJob::
|
144
|
+
old_jobs = GoodJob::Job.where('finished_at <= ?', timestamp)
|
147
145
|
old_jobs = old_jobs.not_discarded unless include_discarded
|
148
146
|
old_jobs_count = old_jobs.count
|
149
147
|
|
150
|
-
GoodJob::Execution.where(job: old_jobs).
|
148
|
+
GoodJob::Execution.where(job: old_jobs).delete_all
|
151
149
|
payload[:destroyed_records_count] = old_jobs_count
|
152
150
|
end
|
153
151
|
end
|