good_job 3.21.4 → 3.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/README.md +54 -29
- data/app/controllers/good_job/jobs_controller.rb +1 -1
- data/app/models/concerns/good_job/filterable.rb +1 -1
- data/app/models/good_job/base_execution.rb +23 -1
- data/app/models/good_job/execution.rb +11 -4
- data/app/models/good_job/job.rb +4 -4
- data/app/views/good_job/shared/_footer.erb +1 -9
- data/app/views/good_job/shared/_navbar.erb +1 -1
- data/app/views/good_job/shared/_secondary_navbar.erb +11 -0
- data/app/views/layouts/good_job/application.html.erb +34 -39
- data/config/locales/de.yml +3 -3
- data/config/locales/en.yml +3 -3
- data/config/locales/es.yml +3 -3
- data/config/locales/fr.yml +3 -3
- data/config/locales/ja.yml +3 -3
- data/config/locales/nl.yml +3 -3
- data/config/locales/ru.yml +3 -3
- data/config/locales/tr.yml +3 -3
- data/config/locales/uk.yml +3 -3
- data/lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb +2 -1
- data/lib/generators/good_job/templates/update/migrations/07_recreate_good_job_cron_indexes_with_conditional.rb.erb +2 -2
- data/lib/generators/good_job/templates/update/migrations/08_create_good_job_labels.rb.erb +15 -0
- data/lib/generators/good_job/templates/update/migrations/09_create_good_job_labels_index.rb.erb +22 -0
- data/lib/generators/good_job/templates/update/migrations/10_remove_good_job_active_id_index.rb.erb +21 -0
- data/lib/good_job/active_job_extensions/labels.rb +32 -0
- data/lib/good_job/version.rb +1 -1
- data/lib/good_job.rb +3 -2
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 699ef4a7d62e1eb7c96644525c9e2239913fb5d23ceafacb13be172e96720532
|
|
4
|
+
data.tar.gz: dcfe3389202698fa321d4c10349758766db20811feafb10024373d54c94dcd2e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 77215885e8d798ba791814bb64f07f2c70d54fa0dd3bb9bbc476dc0464d4c150089bf466e4ed16b648425f78eb9b7e86f0b1259f19e166633f60619347ea3281
|
|
7
|
+
data.tar.gz: 8f1b9a3e16080e331581efbe48bea5060666c4eda460737e1a34508ee6d278abc1fea91e68d486759f39a082b1969c87f84e22a620d7598bc4f9b93d69fce7d8
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [v3.22.0](https://github.com/bensheldon/good_job/tree/v3.22.0) (2024-01-03)
|
|
4
|
+
|
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.21.5...v3.22.0)
|
|
6
|
+
|
|
7
|
+
**Implemented enhancements:**
|
|
8
|
+
|
|
9
|
+
- Add "updated at" info in secondary top navbar [\#1204](https://github.com/bensheldon/good_job/pull/1204) ([sparshalc](https://github.com/sparshalc))
|
|
10
|
+
- Re-add footer with GoodJob version number [\#1201](https://github.com/bensheldon/good_job/pull/1201) ([Pauloparakleto](https://github.com/Pauloparakleto))
|
|
11
|
+
- Add Active Job extension for Labels [\#1188](https://github.com/bensheldon/good_job/pull/1188) ([bensheldon](https://github.com/bensheldon))
|
|
12
|
+
|
|
13
|
+
**Closed issues:**
|
|
14
|
+
|
|
15
|
+
- Limiting by executed jobs count by period [\#1198](https://github.com/bensheldon/good_job/issues/1198)
|
|
16
|
+
- Cron jobs processing in async mode [\#1196](https://github.com/bensheldon/good_job/issues/1196)
|
|
17
|
+
- Dashboard Missing Translation? [\#1192](https://github.com/bensheldon/good_job/issues/1192)
|
|
18
|
+
- Show last update on top nav bar [\#1183](https://github.com/bensheldon/good_job/issues/1183)
|
|
19
|
+
- Wrong quoting of the query to spot new jobs? [\#1179](https://github.com/bensheldon/good_job/issues/1179)
|
|
20
|
+
- \[Possible bug\] good\_job does not honour the wait parameter on retry\_on [\#1174](https://github.com/bensheldon/good_job/issues/1174)
|
|
21
|
+
- Running GoodJob in production with systemd throws an error due to a wrong communication with WatchDog [\#1172](https://github.com/bensheldon/good_job/issues/1172)
|
|
22
|
+
|
|
23
|
+
**Merged pull requests:**
|
|
24
|
+
|
|
25
|
+
- Bump the bundler-dependencies group with 3 updates [\#1202](https://github.com/bensheldon/good_job/pull/1202) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
26
|
+
- Remove duplicated intro sentence in README [\#1195](https://github.com/bensheldon/good_job/pull/1195) ([benoittgt](https://github.com/benoittgt))
|
|
27
|
+
- Fix namespace for `InterruptError` in README [\#1193](https://github.com/bensheldon/good_job/pull/1193) ([padde](https://github.com/padde))
|
|
28
|
+
- Bump github/codeql-action from 2 to 3 [\#1191](https://github.com/bensheldon/good_job/pull/1191) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
29
|
+
- Bump actions/upload-artifact from 3 to 4 [\#1190](https://github.com/bensheldon/good_job/pull/1190) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
30
|
+
- Lock RubyGems version for Ruby \< 3.0 in CI [\#1189](https://github.com/bensheldon/good_job/pull/1189) ([bensheldon](https://github.com/bensheldon))
|
|
31
|
+
- Active Record and Active Job name formatting [\#1182](https://github.com/bensheldon/good_job/pull/1182) ([andyatkinson](https://github.com/andyatkinson))
|
|
32
|
+
- Remove redundant `good_jobs.active_job_id` index [\#1181](https://github.com/bensheldon/good_job/pull/1181) ([andyatkinson](https://github.com/andyatkinson))
|
|
33
|
+
- Add missing word in readme [\#1177](https://github.com/bensheldon/good_job/pull/1177) ([Earlopain](https://github.com/Earlopain))
|
|
34
|
+
|
|
35
|
+
## [v3.21.5](https://github.com/bensheldon/good_job/tree/v3.21.5) (2023-12-12)
|
|
36
|
+
|
|
37
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.21.4...v3.21.5)
|
|
38
|
+
|
|
39
|
+
**Fixed bugs:**
|
|
40
|
+
|
|
41
|
+
- Fix conditional index migration to be rollbackable [\#1176](https://github.com/bensheldon/good_job/pull/1176) ([bensheldon](https://github.com/bensheldon))
|
|
42
|
+
|
|
3
43
|
## [v3.21.4](https://github.com/bensheldon/good_job/tree/v3.21.4) (2023-12-11)
|
|
4
44
|
|
|
5
45
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.21.3...v3.21.4)
|
data/README.md
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
[](https://github.com/bensheldon/good_job/actions/workflows/test.yml?query=branch%3Amain)
|
|
5
5
|
[](https://www.ruby-toolbox.com/projects/good_job)
|
|
6
6
|
|
|
7
|
-
GoodJob is a multithreaded, Postgres-based,
|
|
7
|
+
GoodJob is a multithreaded, Postgres-based, Active Job backend for Ruby on Rails.
|
|
8
8
|
|
|
9
|
-
**Inspired by [Delayed::Job](https://github.com/collectiveidea/delayed_job) and [Que](https://github.com/que-rb/que), GoodJob is designed for maximum compatibility with Ruby on Rails,
|
|
9
|
+
**Inspired by [Delayed::Job](https://github.com/collectiveidea/delayed_job) and [Que](https://github.com/que-rb/que), GoodJob is designed for maximum compatibility with Ruby on Rails, Active Job, and Postgres to be simple and performant for most workloads.**
|
|
10
10
|
|
|
11
|
-
- **Designed for
|
|
11
|
+
- **Designed for Active Job.** Complete support for [async, queues, delays, priorities, timeouts, and retries](https://edgeguides.rubyonrails.org/active_job_basics.html) with near-zero configuration.
|
|
12
12
|
- **Built for Rails.** Fully adopts Ruby on Rails [threading and code execution guidelines](https://guides.rubyonrails.org/threading_and_code_execution.html) with [Concurrent::Ruby](https://github.com/ruby-concurrency/concurrent-ruby).
|
|
13
13
|
- **Backed by Postgres.** Relies upon Postgres integrity, session-level Advisory Locks to provide run-once safety and stay within the limits of `schema.rb`, and LISTEN/NOTIFY to reduce queuing latency.
|
|
14
14
|
- **For most workloads.** Targets full-stack teams, economy-minded solo developers, and applications that enqueue 1-million jobs/day and more.
|
|
@@ -55,7 +55,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
|
55
55
|
- [Exceptions, retries, and reliability](#exceptions-retries-and-reliability)
|
|
56
56
|
- [Exceptions](#exceptions)
|
|
57
57
|
- [Retries](#retries)
|
|
58
|
-
- [
|
|
58
|
+
- [Action Mailer retries](#action-mailer-retries)
|
|
59
59
|
- [Interrupts](#interrupts)
|
|
60
60
|
- [Timeouts](#timeouts)
|
|
61
61
|
- [Optimize queues, threads, and processes](#optimize-queues-threads-and-processes)
|
|
@@ -63,7 +63,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
|
63
63
|
- [Production setup](#production-setup)
|
|
64
64
|
- [Queue performance with Queue Select Limit](#queue-performance-with-queue-select-limit)
|
|
65
65
|
- [Execute jobs async / in-process](#execute-jobs-async--in-process)
|
|
66
|
-
- [Migrate to GoodJob from a different
|
|
66
|
+
- [Migrate to GoodJob from a different Active Job backend](#migrate-to-goodjob-from-a-different-active-job-backend)
|
|
67
67
|
- [Monitor and preserve worked jobs](#monitor-and-preserve-worked-jobs)
|
|
68
68
|
- [Write tests](#write-tests)
|
|
69
69
|
- [PgBouncer compatibility](#pgbouncer-compatibility)
|
|
@@ -103,7 +103,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
|
103
103
|
bin/rails db:migrate:animals
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
1. Configure the
|
|
106
|
+
1. Configure the Active Job adapter:
|
|
107
107
|
|
|
108
108
|
```ruby
|
|
109
109
|
# config/application.rb or config/environments/{RAILS_ENV}.rb
|
|
@@ -116,7 +116,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
|
|
|
116
116
|
YourJob.perform_later
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
-
GoodJob supports all
|
|
119
|
+
GoodJob supports all Active Job features:
|
|
120
120
|
|
|
121
121
|
```ruby
|
|
122
122
|
YourJob.set(queue: :some_queue, wait: 5.minutes, priority: 10).perform_later
|
|
@@ -222,7 +222,7 @@ and this command is not required to be used.
|
|
|
222
222
|
|
|
223
223
|
### Configuration options
|
|
224
224
|
|
|
225
|
-
|
|
225
|
+
Active Job configuration depends on where the code is placed:
|
|
226
226
|
|
|
227
227
|
- `config.active_job.queue_adapter = :good_job` within `config/application.rb` or `config/environments/*.rb`.
|
|
228
228
|
- `ActiveJob::Base.queue_adapter = :good_job` within an initializer (e.g. `config/initializers/active_job.rb`).
|
|
@@ -321,7 +321,7 @@ config.good_job.execution_mode = :external
|
|
|
321
321
|
|
|
322
322
|
Good Job’s general behavior can also be configured via attributes directly on the `GoodJob` module:
|
|
323
323
|
|
|
324
|
-
- **`GoodJob.configure_active_record { ... }`** Inject Active Record configuration into GoodJob's base model, for example, when using [multiple databases with
|
|
324
|
+
- **`GoodJob.configure_active_record { ... }`** Inject Active Record configuration into GoodJob's base model, for example, when using [multiple databases with Active Record](https://guides.rubyonrails.org/active_record_multiple_databases.html) or when other custom configuration is necessary for the Active Record model to connect to the Postgres database. Example:
|
|
325
325
|
|
|
326
326
|
```ruby
|
|
327
327
|
# config/initializers/good_job.rb
|
|
@@ -331,7 +331,7 @@ Good Job’s general behavior can also be configured via attributes directly on
|
|
|
331
331
|
end
|
|
332
332
|
```
|
|
333
333
|
|
|
334
|
-
- **`GoodJob.active_record_parent_class`** (string) Alternatively, modify the
|
|
334
|
+
- **`GoodJob.active_record_parent_class`** (string) Alternatively, modify the Active Record parent class inherited by GoodJob's Active Record model `GoodJob::Job` (defaults to `"ActiveRecord::Base"`). Configure this _The value must be a String to avoid premature initialization of Active Record._
|
|
335
335
|
|
|
336
336
|
You’ll generally want to configure these in `config/initializers/good_job.rb`, like so:
|
|
337
337
|
|
|
@@ -438,9 +438,34 @@ The Dashboard can be set to automatically refresh by checking "Live Poll" in the
|
|
|
438
438
|
|
|
439
439
|
Higher priority numbers run first in all versions of GoodJob v3.x and below. GoodJob v4.x will change job `priority` to give smaller numbers higher priority (default: `0`), in accordance with Active Job's definition of priority (see #524). To opt-in to this behavior now, set `config.good_job.smaller_number_is_higher_priority = true` in your GoodJob initializer or `application.rb`.
|
|
440
440
|
|
|
441
|
+
### Labelled jobs
|
|
442
|
+
|
|
443
|
+
Labels are the recommended way to add context or metadata to specific jobs. For example, all jobs that have a dependency on an email service could be labeled `email`. Using labels requires adding the Active Job extension `GoodJob::ActiveJobExtensions::Labels` to your job class.
|
|
444
|
+
|
|
445
|
+
```ruby
|
|
446
|
+
class ApplicationRecord < ActiveJob::Base
|
|
447
|
+
include GoodJob::ActiveJobExtensions::Labels
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
# Add a default label to every job within the class
|
|
451
|
+
class WelcomeJob < ApplicationRecord
|
|
452
|
+
self.good_job_labels = ["email"]
|
|
453
|
+
|
|
454
|
+
def perform
|
|
455
|
+
# Labels can be inspected from within the job
|
|
456
|
+
puts good_job_labels # => ["email"]
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
# Or add to individual jobs when enqueued
|
|
461
|
+
WelcomeJob.set(good_job_labels: ["email"]).perform_later
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
Labels can be used to search jobs in the Dashboard. For example, to find all jobs labeled `email`, search for `email`.
|
|
465
|
+
|
|
441
466
|
### Concurrency controls
|
|
442
467
|
|
|
443
|
-
GoodJob can extend
|
|
468
|
+
GoodJob can extend Active Job to provide limits on concurrently running jobs, either at time of _enqueue_ or at _perform_. Limiting concurrency can help prevent duplicate, double or unnecessary jobs from being enqueued, or race conditions when performing, for example when interacting with 3rd-party APIs.
|
|
444
469
|
|
|
445
470
|
```ruby
|
|
446
471
|
class MyJob < ApplicationJob
|
|
@@ -469,7 +494,7 @@ class MyJob < ApplicationJob
|
|
|
469
494
|
|
|
470
495
|
# A unique key to be globally locked against.
|
|
471
496
|
# Can be String or Lambda/Proc that is invoked in the context of the job.
|
|
472
|
-
# Note: Arguments passed to #perform_later can be accessed through
|
|
497
|
+
# Note: Arguments passed to #perform_later can be accessed through Active Job's `arguments` method
|
|
473
498
|
# which is an array containing positional arguments and, optionally, a kwarg hash.
|
|
474
499
|
key: -> { "MyJob-#{arguments.first}-#{arguments.last[:version]}" } # MyJob.perform_later("Alice", version: 'v2') => "MyJob-Alice-v2"
|
|
475
500
|
)
|
|
@@ -549,11 +574,11 @@ active_jobs = GoodJob::Bulk.enqueue do
|
|
|
549
574
|
# If an exception is raised within this block, no jobs will be inserted.
|
|
550
575
|
end
|
|
551
576
|
|
|
552
|
-
# All
|
|
577
|
+
# All Active Job instances are returned from GoodJob::Bulk.enqueue.
|
|
553
578
|
# Jobs that have been successfully enqueued have a `provider_job_id` set.
|
|
554
579
|
active_jobs.all?(&:provider_job_id)
|
|
555
580
|
|
|
556
|
-
# Bulk enqueue
|
|
581
|
+
# Bulk enqueue Active Job instances directly without using `.perform_later`:
|
|
557
582
|
GoodJob::Bulk.enqueue(MyJob.new, AnotherJob.new)
|
|
558
583
|
```
|
|
559
584
|
|
|
@@ -737,7 +762,7 @@ GoodJob follows semantic versioning, though updates may be encouraged through de
|
|
|
737
762
|
|
|
738
763
|
Upgrading between minor versions (e.g. v1.4 to v1.5) should not introduce breaking changes, but can introduce new deprecation warnings and database migration warnings.
|
|
739
764
|
|
|
740
|
-
Database migrations introduced in minor releases are _not required_ to be applied until the next major release. If you would like apply newly introduced migrations immediately, assert `GoodJob.migrated?` in your application's test suite.
|
|
765
|
+
Database migrations introduced in minor releases are _not required_ to be applied until the next major release. If you would like to apply newly introduced migrations immediately, assert `GoodJob.migrated?` in your application's test suite.
|
|
741
766
|
|
|
742
767
|
To perform upgrades to the GoodJob database tables:
|
|
743
768
|
|
|
@@ -791,7 +816,7 @@ Notable changes:
|
|
|
791
816
|
- Renames `:async_server` execution mode to `:async`; renames prior `:async` execution mode to `:async_all`.
|
|
792
817
|
- Sets default Development environment's execution mode to `:async` with disabled polling.
|
|
793
818
|
- Excludes performing jobs from `enqueue_limit`'s count in `GoodJob::ActiveJobExtensions::Concurrency`.
|
|
794
|
-
- Triggers `GoodJob.on_thread_error` for unhandled
|
|
819
|
+
- Triggers `GoodJob.on_thread_error` for unhandled Active Job exceptions.
|
|
795
820
|
- Renames `GoodJob.reperform_jobs_on_standard_error` accessor to `GoodJob.retry_on_unhandled_error`.
|
|
796
821
|
- Renames `GoodJob::Adapter.shutdown(wait:)` argument to `GoodJob::Adapter.shutdown(timeout:)`.
|
|
797
822
|
- Changes Advisory Lock key format from `good_jobs[ROW_ID]` to `good_jobs-[ACTIVE_JOB_ID]`.
|
|
@@ -801,11 +826,11 @@ Notable changes:
|
|
|
801
826
|
|
|
802
827
|
### Exceptions, retries, and reliability
|
|
803
828
|
|
|
804
|
-
GoodJob guarantees that a completely-performed job will run once and only once. GoodJob fully supports
|
|
829
|
+
GoodJob guarantees that a completely-performed job will run once and only once. GoodJob fully supports Active Job's built-in functionality for error handling, retries and timeouts.
|
|
805
830
|
|
|
806
831
|
#### Exceptions
|
|
807
832
|
|
|
808
|
-
|
|
833
|
+
Active Job provides [tools for rescuing and retrying exceptions](https://guides.rubyonrails.org/active_job_basics.html#exceptions), including `retry_on`, `discard_on`, `rescue_from` that will rescue exceptions before they get to GoodJob.
|
|
809
834
|
|
|
810
835
|
If errors do reach GoodJob, you can assign a callable to `GoodJob.on_thread_error` to be notified. For example, to log errors to an exception monitoring service like Sentry (or Bugsnag, Airbrake, Honeybadger, etc.):
|
|
811
836
|
|
|
@@ -816,9 +841,9 @@ GoodJob.on_thread_error = -> (exception) { Rails.error.report(exception) }
|
|
|
816
841
|
|
|
817
842
|
#### Retries
|
|
818
843
|
|
|
819
|
-
By default, GoodJob relies on
|
|
844
|
+
By default, GoodJob relies on Active Job's retry functionality.
|
|
820
845
|
|
|
821
|
-
|
|
846
|
+
Active Job can be configured to retry an infinite number of times, with a polynomial backoff. Using Active Job's `retry_on` prevents exceptions from reaching GoodJob:
|
|
822
847
|
|
|
823
848
|
```ruby
|
|
824
849
|
class ApplicationJob < ActiveJob::Base
|
|
@@ -860,7 +885,7 @@ end
|
|
|
860
885
|
|
|
861
886
|
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.
|
|
862
887
|
|
|
863
|
-
####
|
|
888
|
+
#### Action Mailer retries
|
|
864
889
|
|
|
865
890
|
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`.
|
|
866
891
|
|
|
@@ -886,16 +911,16 @@ might also be configured to use (deprecated now) `ActionMailer::DeliveryJob`.
|
|
|
886
911
|
|
|
887
912
|
Jobs will be automatically retried if the process is interrupted while performing a job, for example as the result of a `SIGKILL` or power failure.
|
|
888
913
|
|
|
889
|
-
If you need more control over interrupt-caused retries, include the `GoodJob::ActiveJobExtensions::InterruptErrors` extension in your job class. When an interrupted job is retried, the extension will raise a `GoodJob::InterruptError` exception within the job, which allows you to use
|
|
914
|
+
If you need more control over interrupt-caused retries, include the `GoodJob::ActiveJobExtensions::InterruptErrors` extension in your job class. When an interrupted job is retried, the extension will raise a `GoodJob::InterruptError` exception within the job, which allows you to use Active Job's `retry_on` and `discard_on` to control the behavior of the job.
|
|
890
915
|
|
|
891
916
|
```ruby
|
|
892
917
|
class MyJob < ApplicationJob
|
|
893
918
|
# The extension must be included before other extensions
|
|
894
919
|
include GoodJob::ActiveJobExtensions::InterruptErrors
|
|
895
920
|
# Discard the job if it is interrupted
|
|
896
|
-
discard_on InterruptError
|
|
921
|
+
discard_on GoodJob::InterruptError
|
|
897
922
|
# Retry the job if it is interrupted
|
|
898
|
-
retry_on InterruptError, wait: 0, attempts: Float::INFINITY
|
|
923
|
+
retry_on GoodJob::InterruptError, wait: 0, attempts: Float::INFINITY
|
|
899
924
|
end
|
|
900
925
|
```
|
|
901
926
|
|
|
@@ -1176,9 +1201,9 @@ Depending on your application configuration, you may need to take additional ste
|
|
|
1176
1201
|
|
|
1177
1202
|
If you are using cron-style jobs, you might also want to look at your Passenger configuration, especially at [`passenger_pool_idle_time`](https://www.phusionpassenger.com/library/config/nginx/reference/#passenger_pool_idle_time) and [`passenger_min_instances`](https://www.phusionpassenger.com/library/config/nginx/reference/#passenger_min_instances) to make sure there's always at least once process running that can execute cron-style scheduled jobs. See also [Passenger's optimization guide](https://www.phusionpassenger.com/library/config/nginx/optimization/#minimizing-process-spawning) for more information.
|
|
1178
1203
|
|
|
1179
|
-
### Migrate to GoodJob from a different
|
|
1204
|
+
### Migrate to GoodJob from a different Active Job backend
|
|
1180
1205
|
|
|
1181
|
-
If your application is already using an
|
|
1206
|
+
If your application is already using an Active Job backend, you will need to install GoodJob to enqueue and perform newly created jobs _and_ finish performing pre-existing jobs on the previous backend.
|
|
1182
1207
|
|
|
1183
1208
|
1. Enqueue newly created jobs on GoodJob either entirely by setting `ActiveJob::Base.queue_adapter = :good_job` or progressively via individual job classes:
|
|
1184
1209
|
|
|
@@ -1198,7 +1223,7 @@ If your application is already using an ActiveJob backend, you will need to inst
|
|
|
1198
1223
|
worker: bundle exec que ./config/environment.rb & bundle exec good_job & wait -n
|
|
1199
1224
|
```
|
|
1200
1225
|
|
|
1201
|
-
1. Once you are confident that no unperformed jobs remain in the previous
|
|
1226
|
+
1. Once you are confident that no unperformed jobs remain in the previous Active Job backend, code and configuration for that backend can be completely removed.
|
|
1202
1227
|
|
|
1203
1228
|
### Monitor and preserve worked jobs
|
|
1204
1229
|
|
|
@@ -1271,7 +1296,7 @@ A workaround to this limitation is to make a direct database connection availabl
|
|
|
1271
1296
|
url: postgres://database_host/my_database
|
|
1272
1297
|
```
|
|
1273
1298
|
|
|
1274
|
-
1. Create a new
|
|
1299
|
+
1. Create a new Active Record base class that uses the direct database connection
|
|
1275
1300
|
|
|
1276
1301
|
```ruby
|
|
1277
1302
|
# app/models/application_direct_record.rb
|
|
@@ -1282,7 +1307,7 @@ A workaround to this limitation is to make a direct database connection availabl
|
|
|
1282
1307
|
end
|
|
1283
1308
|
```
|
|
1284
1309
|
|
|
1285
|
-
1. Configure GoodJob to use the newly created
|
|
1310
|
+
1. Configure GoodJob to use the newly created Active Record base class:
|
|
1286
1311
|
|
|
1287
1312
|
```ruby
|
|
1288
1313
|
# config/initializers/good_job.rb
|
|
@@ -96,7 +96,7 @@ module GoodJob
|
|
|
96
96
|
def redirect_on_error(exception)
|
|
97
97
|
alert = case exception
|
|
98
98
|
when GoodJob::Job::AdapterNotGoodJobError
|
|
99
|
-
"
|
|
99
|
+
"Active Job Queue Adapter must be GoodJob."
|
|
100
100
|
when GoodJob::Job::ActionForStateMismatchError
|
|
101
101
|
"Job is not in an appropriate state for this action."
|
|
102
102
|
else
|
|
@@ -34,7 +34,7 @@ module GoodJob
|
|
|
34
34
|
query = query.to_s.strip
|
|
35
35
|
next if query.blank?
|
|
36
36
|
|
|
37
|
-
tsvector = "(to_tsvector('english',
|
|
37
|
+
tsvector = "(to_tsvector('english', id::text) || to_tsvector('english', COALESCE(active_job_id::text, '')) || to_tsvector('english', serialized_params) || to_tsvector('english', COALESCE(error, ''))#{" || to_tsvector('english', COALESCE(array_to_string(labels, ' '), ''))" if labels_migrated?})"
|
|
38
38
|
to_tsquery_function = database_supports_websearch_to_tsquery? ? 'websearch_to_tsquery' : 'plainto_tsquery'
|
|
39
39
|
where("#{tsvector} @@ #{to_tsquery_function}(?)", query)
|
|
40
40
|
.order(sanitize_sql_for_order([Arel.sql("ts_rank(#{tsvector}, #{to_tsquery_function}(?))"), query]) => 'DESC')
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module GoodJob
|
|
4
|
-
#
|
|
4
|
+
# Active Record model to share behavior between {Job} and {Execution} models
|
|
5
5
|
# which both read out of the same table.
|
|
6
6
|
class BaseExecution < BaseRecord
|
|
7
7
|
include AdvisoryLockable
|
|
@@ -56,6 +56,27 @@ module GoodJob
|
|
|
56
56
|
migration_pending_warning!
|
|
57
57
|
false
|
|
58
58
|
end
|
|
59
|
+
|
|
60
|
+
def labels_migrated?
|
|
61
|
+
return true if columns_hash["labels"].present?
|
|
62
|
+
|
|
63
|
+
migration_pending_warning!
|
|
64
|
+
false
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def labels_indices_migrated?
|
|
68
|
+
return true if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_labels)
|
|
69
|
+
|
|
70
|
+
migration_pending_warning!
|
|
71
|
+
false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def active_job_id_index_removal_migrated?
|
|
75
|
+
return true unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id)
|
|
76
|
+
|
|
77
|
+
migration_pending_warning!
|
|
78
|
+
false
|
|
79
|
+
end
|
|
59
80
|
end
|
|
60
81
|
|
|
61
82
|
# The ActiveJob job class, as a string
|
|
@@ -88,6 +109,7 @@ module GoodJob
|
|
|
88
109
|
.tap do |job_data|
|
|
89
110
|
job_data["provider_job_id"] = id
|
|
90
111
|
job_data["good_job_concurrency_key"] = concurrency_key if concurrency_key
|
|
112
|
+
job_data["good_job_labels"] = Array(labels) if self.class.labels_migrated? && labels.present?
|
|
91
113
|
end
|
|
92
114
|
end
|
|
93
115
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module GoodJob
|
|
4
|
-
#
|
|
4
|
+
# Active Record model that represents an +ActiveJob+ job.
|
|
5
5
|
class Execution < BaseExecution
|
|
6
6
|
# Raised if something attempts to execute a previously completed Execution again.
|
|
7
7
|
PreviouslyPerformedError = Class.new(StandardError)
|
|
@@ -150,9 +150,9 @@ module GoodJob
|
|
|
150
150
|
# @return [ActiveRecord::Relation]
|
|
151
151
|
scope :schedule_ordered, -> { order(coalesce_scheduled_at_created_at.asc) }
|
|
152
152
|
|
|
153
|
-
# Get
|
|
154
|
-
# provided, get all jobs
|
|
155
|
-
# destroys jobs after they
|
|
153
|
+
# Get completed jobs before the given timestamp. If no timestamp is
|
|
154
|
+
# provided, get *all* completed jobs. By default, GoodJob
|
|
155
|
+
# destroys jobs after they're completed, meaning this returns no jobs.
|
|
156
156
|
# However, if you have changed {GoodJob.preserve_job_records}, this may
|
|
157
157
|
# find completed Jobs.
|
|
158
158
|
# @!method finished(timestamp = nil)
|
|
@@ -225,6 +225,13 @@ module GoodJob
|
|
|
225
225
|
execution_args[:scheduled_at] = Time.zone.at(active_job.scheduled_at) if active_job.scheduled_at
|
|
226
226
|
execution_args[:concurrency_key] = active_job.good_job_concurrency_key if active_job.respond_to?(:good_job_concurrency_key)
|
|
227
227
|
|
|
228
|
+
if active_job.respond_to?(:good_job_labels) && active_job.good_job_labels.any? && labels_migrated?
|
|
229
|
+
labels = active_job.good_job_labels.dup
|
|
230
|
+
labels.map! { |label| label.to_s.strip.presence }
|
|
231
|
+
labels.tap(&:compact!).tap(&:uniq!)
|
|
232
|
+
execution_args[:labels] = labels
|
|
233
|
+
end
|
|
234
|
+
|
|
228
235
|
reenqueued_current_execution = CurrentThread.active_job_id && CurrentThread.active_job_id == active_job.job_id
|
|
229
236
|
current_execution = CurrentThread.execution
|
|
230
237
|
|
data/app/models/good_job/job.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module GoodJob
|
|
4
|
-
#
|
|
4
|
+
# Active Record model that represents an +ActiveJob+ job.
|
|
5
5
|
# There is not a table in the database whose discrete rows represents "Jobs".
|
|
6
6
|
# The +good_jobs+ table is a table of individual {GoodJob::Execution}s that share the same +active_job_id+.
|
|
7
7
|
# A single row from the +good_jobs+ table of executions is fetched to represent a Job.
|
|
@@ -9,7 +9,7 @@ module GoodJob
|
|
|
9
9
|
class Job < BaseExecution
|
|
10
10
|
# Raised when an inappropriate action is applied to a Job based on its state.
|
|
11
11
|
ActionForStateMismatchError = Class.new(StandardError)
|
|
12
|
-
# Raised when
|
|
12
|
+
# Raised when GoodJob is not configured as the Active Job Queue Adapter
|
|
13
13
|
AdapterNotGoodJobError = Class.new(StandardError)
|
|
14
14
|
# Attached to a Job's Execution when the Job is discarded.
|
|
15
15
|
DiscardJobError = Class.new(StandardError)
|
|
@@ -60,7 +60,7 @@ module GoodJob
|
|
|
60
60
|
|
|
61
61
|
scope :unfinished_undiscrete, -> { where(finished_at: nil, retried_good_job_id: nil, is_discrete: [nil, false]) }
|
|
62
62
|
|
|
63
|
-
# The job's
|
|
63
|
+
# The job's Active Job UUID
|
|
64
64
|
# @return [String]
|
|
65
65
|
def id
|
|
66
66
|
active_job_id
|
|
@@ -101,7 +101,7 @@ module GoodJob
|
|
|
101
101
|
executions.first
|
|
102
102
|
end
|
|
103
103
|
|
|
104
|
-
# The number of times this job has been executed, according to
|
|
104
|
+
# The number of times this job has been executed, according to Active Job's serialized state.
|
|
105
105
|
# @return [Numeric]
|
|
106
106
|
def executions_count
|
|
107
107
|
aj_count = serialized_params.fetch('executions', 0)
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
<footer class="footer mt-auto py-3 bg-body-tertiary border-top text-muted small" id="footer" data-live-poll-region="footer">
|
|
2
2
|
<div class="container-fluid">
|
|
3
|
-
|
|
4
|
-
<div class="col-6">
|
|
5
|
-
<%= t(".last_update_html", time: Time.current.utc.iso8601) %>
|
|
6
|
-
</div>
|
|
7
|
-
|
|
8
|
-
<div class="col-6 text-end">
|
|
9
|
-
<%= t(".wording") %>
|
|
10
|
-
</div>
|
|
11
|
-
</div>
|
|
3
|
+
GoodJob v<%= GoodJob::VERSION %>
|
|
12
4
|
</div>
|
|
13
5
|
</footer>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<nav class="navbar navbar-expand-lg border-bottom bg-body sticky-top
|
|
1
|
+
<nav class="navbar navbar-expand-lg border-bottom bg-body sticky-top">
|
|
2
2
|
<div class="container-fluid">
|
|
3
3
|
<%= link_to t(".name"), root_path, class: "navbar-brand mb-0 h1" %>
|
|
4
4
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<nav class="navbar p-1 shadow-sm mt-auto border-bottom text-muted small" id="secondary-navbar" data-live-poll-region="secondary-navbar">
|
|
2
|
+
<div class="container-fluid">
|
|
3
|
+
<div class="flex-fill d-none d-sm-block ">
|
|
4
|
+
<%= t(".inspiration") %>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="flex-fill text-end">
|
|
7
|
+
<% last_updated_at = Time.current.utc.iso8601 %>
|
|
8
|
+
<%= t(".last_updated") %> <time id="page-updated-at" datetime="<%= last_updated_at %>"><%== last_updated_at %></time>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
</nav>
|
|
@@ -1,44 +1,39 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="<%= I18n.locale %>" data-bs-theme="auto">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// Ensure theme is updated before dom loads to avoid flash of style
|
|
24
|
-
let theme = localStorage.getItem('good_job-theme');
|
|
25
|
-
if (!["light", "dark"].includes(theme)) {
|
|
3
|
+
<head>
|
|
4
|
+
<title>Good Job Dashboard</title>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
|
|
7
|
+
<%= csrf_meta_tags %>
|
|
8
|
+
<%= csp_meta_tag %>
|
|
9
|
+
<%# Do not use asset tag helpers to avoid paths being overriden by config.asset_host %>
|
|
10
|
+
<%= tag.link rel: "stylesheet", href: frontend_static_path(:bootstrap, format: :css, v: GoodJob::VERSION, locale: nil), nonce: content_security_policy_nonce %>
|
|
11
|
+
<%= tag.link rel: "stylesheet", href: frontend_static_path(:style, format: :css, v: GoodJob::VERSION, locale: nil), nonce: content_security_policy_nonce %>
|
|
12
|
+
<%= tag.script "", src: frontend_static_path(:bootstrap, format: :js, v: GoodJob::VERSION, locale: nil), nonce: content_security_policy_nonce %>
|
|
13
|
+
<%= tag.script "", src: frontend_static_path(:chartjs, format: :js, v: GoodJob::VERSION, locale: nil), nonce: content_security_policy_nonce %>
|
|
14
|
+
<%= tag.script "", src: frontend_static_path(:rails_ujs, format: :js, v: GoodJob::VERSION, locale: nil), nonce: content_security_policy_nonce %>
|
|
15
|
+
<%= tag.script "", src: frontend_static_path(:es_module_shims, format: :js, v: GoodJob::VERSION, locale: nil), async: true, nonce: content_security_policy_nonce %>
|
|
16
|
+
<% importmaps = GoodJob::FrontendsController.js_modules.keys.index_with { |module_name| frontend_module_path(module_name, format: :js, locale: nil, v: GoodJob::VERSION) } %>
|
|
17
|
+
<%= tag.script({ imports: importmaps }.to_json.html_safe, type: "importmap", nonce: content_security_policy_nonce) %>
|
|
18
|
+
<%= tag.script "", type: "module", nonce: content_security_policy_nonce do %> import "application"; <% end %>
|
|
19
|
+
<%= tag.script "", nonce: content_security_policy_nonce do %>
|
|
20
|
+
// Ensure theme is updated before dom loads to avoid flash of style
|
|
21
|
+
let theme = localStorage.getItem('good_job-theme');
|
|
22
|
+
if (!["light", "dark"].includes(theme)) {
|
|
26
23
|
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
</head>
|
|
31
|
-
<body>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
}
|
|
25
|
+
document.documentElement.setAttribute('data-bs-theme', theme);
|
|
26
|
+
<% end %>
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<div class="d-flex flex-column min-vh-100">
|
|
30
|
+
<%= render "good_job/shared/navbar" %>
|
|
31
|
+
<%= render "good_job/shared/secondary_navbar" %>
|
|
32
|
+
<div class="container-fluid flex-grow-1 relative">
|
|
33
|
+
<%= render "good_job/shared/alert" %>
|
|
34
|
+
<%= yield %>
|
|
35
|
+
</div>
|
|
36
|
+
<%= render "good_job/shared/footer" %>
|
|
39
37
|
</div>
|
|
40
|
-
|
|
41
|
-
<%= render "good_job/shared/footer" %>
|
|
42
|
-
</div>
|
|
43
|
-
</body>
|
|
38
|
+
</body>
|
|
44
39
|
</html>
|
data/config/locales/de.yml
CHANGED
|
@@ -219,9 +219,6 @@ de:
|
|
|
219
219
|
placeholder: Suchen Sie nach Klasse, Job-ID, Jobparametern und Fehlertext.
|
|
220
220
|
queue_name: Warteschlangenname
|
|
221
221
|
search: Suchen
|
|
222
|
-
footer:
|
|
223
|
-
last_update_html: Zuletzt aktualisiert <time id="page-updated-at" datetime="%{time}">%{time}</time>
|
|
224
|
-
wording: Denk daran, auch du machst einen guten Job!
|
|
225
222
|
navbar:
|
|
226
223
|
batches: Batches
|
|
227
224
|
cron_schedules: Cron
|
|
@@ -234,6 +231,9 @@ de:
|
|
|
234
231
|
dark: Dunkel
|
|
235
232
|
light: Licht
|
|
236
233
|
theme: Thema
|
|
234
|
+
secondary_navbar:
|
|
235
|
+
inspiration: Denk daran, auch du machst einen guten Job!
|
|
236
|
+
last_updated: Zuletzt aktualisiert
|
|
237
237
|
status:
|
|
238
238
|
discarded: Ausrangiert
|
|
239
239
|
queued: In der Warteschlange
|
data/config/locales/en.yml
CHANGED
|
@@ -219,9 +219,6 @@ en:
|
|
|
219
219
|
placeholder: Search by class, job id, job params, and error text.
|
|
220
220
|
queue_name: Queue name
|
|
221
221
|
search: Search
|
|
222
|
-
footer:
|
|
223
|
-
last_update_html: Last updated <time id="page-updated-at" datetime="%{time}">%{time}</time>
|
|
224
|
-
wording: Remember, you're doing a Good Job too!
|
|
225
222
|
navbar:
|
|
226
223
|
batches: Batches
|
|
227
224
|
cron_schedules: Cron
|
|
@@ -234,6 +231,9 @@ en:
|
|
|
234
231
|
dark: Dark
|
|
235
232
|
light: Light
|
|
236
233
|
theme: Theme
|
|
234
|
+
secondary_navbar:
|
|
235
|
+
inspiration: Remember, you're doing a Good Job too!
|
|
236
|
+
last_updated: Last updated
|
|
237
237
|
status:
|
|
238
238
|
discarded: Discarded
|
|
239
239
|
queued: Queued
|
data/config/locales/es.yml
CHANGED
|
@@ -217,9 +217,6 @@ es:
|
|
|
217
217
|
placeholder: Buscar por clase, id de tarea, parámetros y mensaje de error.
|
|
218
218
|
queue_name: Nombre de la cola
|
|
219
219
|
search: Buscar
|
|
220
|
-
footer:
|
|
221
|
-
last_update_html: Última actualización <time id="page-updated-at" datetime="%{time}">%{time}</time>
|
|
222
|
-
wording: "¡Recuerda, también tú estás haciendo un buen trabajo!"
|
|
223
220
|
navbar:
|
|
224
221
|
batches: Batches
|
|
225
222
|
cron_schedules: Cron
|
|
@@ -232,6 +229,9 @@ es:
|
|
|
232
229
|
dark: Oscuro
|
|
233
230
|
light: Luz
|
|
234
231
|
theme: Tema
|
|
232
|
+
secondary_navbar:
|
|
233
|
+
inspiration: "¡Recuerda, también tú estás haciendo un buen trabajo!"
|
|
234
|
+
last_updated: Última actualización
|
|
235
235
|
status:
|
|
236
236
|
discarded:
|
|
237
237
|
one: Descartada
|
data/config/locales/fr.yml
CHANGED
|
@@ -219,9 +219,6 @@ fr:
|
|
|
219
219
|
placeholder: Recherche par classe, ID de job, paramètres de job et texte d'erreur.
|
|
220
220
|
queue_name: Nom de la file d'attente
|
|
221
221
|
search: Recherche
|
|
222
|
-
footer:
|
|
223
|
-
last_update_html: Dernière mise à jour <time id="page-updated-at" datetime="%{time}">%{time}</time>
|
|
224
|
-
wording: N'oublie pas, toi aussi tu fais du bon boulot !
|
|
225
222
|
navbar:
|
|
226
223
|
batches: Lots
|
|
227
224
|
cron_schedules: Cron
|
|
@@ -234,6 +231,9 @@ fr:
|
|
|
234
231
|
dark: Sombre
|
|
235
232
|
light: Lumière
|
|
236
233
|
theme: Thème
|
|
234
|
+
secondary_navbar:
|
|
235
|
+
inspiration: N'oublie pas, toi aussi tu fais du bon boulot !
|
|
236
|
+
last_updated: Dernière mise à jour
|
|
237
237
|
status:
|
|
238
238
|
discarded: Mis au rebut
|
|
239
239
|
queued: À la file
|
data/config/locales/ja.yml
CHANGED
|
@@ -219,9 +219,6 @@ ja:
|
|
|
219
219
|
placeholder: クラス名、ジョブID、ジョブパラメータ、エラーテキストで検索
|
|
220
220
|
queue_name: キュー名
|
|
221
221
|
search: 検索
|
|
222
|
-
footer:
|
|
223
|
-
last_update_html: 最終更新 <time id="page-updated-at" datetime="%{time}">%{time}</time>
|
|
224
|
-
wording: Remember, you're doing a Good Job too!
|
|
225
222
|
navbar:
|
|
226
223
|
batches: バッチ
|
|
227
224
|
cron_schedules: Cron
|
|
@@ -234,6 +231,9 @@ ja:
|
|
|
234
231
|
dark: 暗い
|
|
235
232
|
light: ライト
|
|
236
233
|
theme: テーマ
|
|
234
|
+
secondary_navbar:
|
|
235
|
+
inspiration: 覚えておいてください、あなたも良い仕事をしています!
|
|
236
|
+
last_updated: 最終更新
|
|
237
237
|
status:
|
|
238
238
|
discarded: 破棄済み
|
|
239
239
|
queued: 処理待ち
|
data/config/locales/nl.yml
CHANGED
|
@@ -219,9 +219,6 @@ nl:
|
|
|
219
219
|
placeholder: Zoek op klasse, taak-ID, taakparameters en fouttekst.
|
|
220
220
|
queue_name: Wachtrij naam
|
|
221
221
|
search: Zoekopdracht
|
|
222
|
-
footer:
|
|
223
|
-
last_update_html: Laatst bijgewerkt <time id="page-updated-at" datetime="%{time}">%{time}</time>
|
|
224
|
-
wording: 'Onthoud: jij levert ook goed werk!'
|
|
225
222
|
navbar:
|
|
226
223
|
batches: Batches
|
|
227
224
|
cron_schedules: Cron
|
|
@@ -234,6 +231,9 @@ nl:
|
|
|
234
231
|
dark: Donker
|
|
235
232
|
light: Licht
|
|
236
233
|
theme: Thema
|
|
234
|
+
secondary_navbar:
|
|
235
|
+
inspiration: 'Onthoud: jij levert ook goed werk!'
|
|
236
|
+
last_updated: Laatst bijgewerkt
|
|
237
237
|
status:
|
|
238
238
|
discarded: weggegooid
|
|
239
239
|
queued: In de wachtrij
|
data/config/locales/ru.yml
CHANGED
|
@@ -245,9 +245,6 @@ ru:
|
|
|
245
245
|
placeholder: Поиск по классу, идентификатору задания, параметрам задания и тексту ошибки.
|
|
246
246
|
queue_name: Имя очереди
|
|
247
247
|
search: Поиск
|
|
248
|
-
footer:
|
|
249
|
-
last_update_html: Последнее обновление <time id="page-updated-at" datetime="%{time}">%{time}</time>
|
|
250
|
-
wording: Запомни, ты делаешь Good Job тоже!
|
|
251
248
|
navbar:
|
|
252
249
|
batches: Batches
|
|
253
250
|
cron_schedules: Cron
|
|
@@ -260,6 +257,9 @@ ru:
|
|
|
260
257
|
dark: Темный
|
|
261
258
|
light: Свет
|
|
262
259
|
theme: Тема
|
|
260
|
+
secondary_navbar:
|
|
261
|
+
inspiration: Запомни, ты делаешь Good Job тоже!
|
|
262
|
+
last_updated: Последнее обновление
|
|
263
263
|
status:
|
|
264
264
|
discarded: Отброшено
|
|
265
265
|
queued: В очереди
|
data/config/locales/tr.yml
CHANGED
|
@@ -219,9 +219,6 @@ tr:
|
|
|
219
219
|
placeholder: Sınıfa, iş kimliğine, iş parametrelerine ve hata metnine göre ara.
|
|
220
220
|
queue_name: Kuyruk adı
|
|
221
221
|
search: Ara
|
|
222
|
-
footer:
|
|
223
|
-
last_update_html: Son güncelleme <time id="page-updated-at" datetime="%{time}">%{time}</time>
|
|
224
|
-
wording: Unutmayın, siz de iyi bir iş yapıyorsunuz!
|
|
225
222
|
navbar:
|
|
226
223
|
batches: Toplu İşler
|
|
227
224
|
cron_schedules: Cron
|
|
@@ -234,6 +231,9 @@ tr:
|
|
|
234
231
|
dark: Karanlık
|
|
235
232
|
light: Işık
|
|
236
233
|
theme: Tema
|
|
234
|
+
secondary_navbar:
|
|
235
|
+
inspiration: Unutmayın, siz de iyi bir iş yapıyorsunuz!
|
|
236
|
+
last_updated: Son güncelleme
|
|
237
237
|
status:
|
|
238
238
|
discarded: İptal Edildi
|
|
239
239
|
queued: Sırada
|
data/config/locales/uk.yml
CHANGED
|
@@ -245,9 +245,6 @@ uk:
|
|
|
245
245
|
placeholder: Пошук за класом, ідентифікатором роботи, параметрами роботи та текстом помилки.
|
|
246
246
|
queue_name: Назва черги
|
|
247
247
|
search: Пошук
|
|
248
|
-
footer:
|
|
249
|
-
last_update_html: Останнє оновлення <time id="page-updated-at" datetime="%{time}">%{time}</time>
|
|
250
|
-
wording: Пам'ятайте, ви теж робите хорошу роботу!
|
|
251
248
|
navbar:
|
|
252
249
|
batches: Batches
|
|
253
250
|
cron_schedules: Cron
|
|
@@ -260,6 +257,9 @@ uk:
|
|
|
260
257
|
dark: Темний
|
|
261
258
|
light: світло
|
|
262
259
|
theme: Тема
|
|
260
|
+
secondary_navbar:
|
|
261
|
+
inspiration: Пам'ятайте, ви теж робите хорошу роботу!
|
|
262
|
+
last_updated: Останнє оновлення
|
|
263
263
|
status:
|
|
264
264
|
discarded: Відхилено
|
|
265
265
|
queued: У черзі
|
|
@@ -29,6 +29,7 @@ class CreateGoodJobs < ActiveRecord::Migration<%= migration_version %>
|
|
|
29
29
|
t.integer :executions_count
|
|
30
30
|
t.text :job_class
|
|
31
31
|
t.integer :error_event, limit: 2
|
|
32
|
+
t.text :labels, array: true
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
create_table :good_job_batches, id: :uuid do |t|
|
|
@@ -76,12 +77,12 @@ class CreateGoodJobs < ActiveRecord::Migration<%= migration_version %>
|
|
|
76
77
|
add_index :good_jobs, :concurrency_key, where: "(finished_at IS NULL)", name: :index_good_jobs_on_concurrency_key_when_unfinished
|
|
77
78
|
add_index :good_jobs, [:cron_key, :created_at], where: "(cron_key IS NOT NULL)", name: :index_good_jobs_on_cron_key_and_created_at_cond
|
|
78
79
|
add_index :good_jobs, [:cron_key, :cron_at], where: "(cron_key IS NOT NULL)", unique: true, name: :index_good_jobs_on_cron_key_and_cron_at_cond
|
|
79
|
-
add_index :good_jobs, [:active_job_id], name: :index_good_jobs_on_active_job_id
|
|
80
80
|
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
|
|
81
81
|
add_index :good_jobs, [:priority, :created_at], order: { priority: "DESC NULLS LAST", created_at: :asc },
|
|
82
82
|
where: "finished_at IS NULL", name: :index_good_jobs_jobs_on_priority_created_at_when_unfinished
|
|
83
83
|
add_index :good_jobs, [:batch_id], where: "batch_id IS NOT NULL"
|
|
84
84
|
add_index :good_jobs, [:batch_callback_id], where: "batch_callback_id IS NOT NULL"
|
|
85
|
+
add_index :good_jobs, :labels, using: :gin, where: "(labels IS NOT NULL)", name: :index_good_jobs_on_labels
|
|
85
86
|
|
|
86
87
|
add_index :good_job_executions, [:active_job_id, :created_at], name: :index_good_job_executions_on_active_job_id_and_created_at
|
|
87
88
|
end
|
|
@@ -25,11 +25,11 @@ class RecreateGoodJobCronIndexesWithConditional < ActiveRecord::Migration<%= mig
|
|
|
25
25
|
|
|
26
26
|
dir.down do
|
|
27
27
|
unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_created_at)
|
|
28
|
-
add_index :good_jobs, [:cron_key, :created_at],
|
|
28
|
+
add_index :good_jobs, [:cron_key, :created_at],
|
|
29
29
|
name: :index_good_jobs_on_cron_key_and_created_at, algorithm: :concurrently
|
|
30
30
|
end
|
|
31
31
|
unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_cron_at)
|
|
32
|
-
add_index :good_jobs, [:cron_key, :cron_at],
|
|
32
|
+
add_index :good_jobs, [:cron_key, :cron_at], unique: true,
|
|
33
33
|
name: :index_good_jobs_on_cron_key_and_cron_at, algorithm: :concurrently
|
|
34
34
|
end
|
|
35
35
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateGoodJobLabels < ActiveRecord::Migration<%= migration_version %>
|
|
4
|
+
def change
|
|
5
|
+
reversible do |dir|
|
|
6
|
+
dir.up do
|
|
7
|
+
# Ensure this incremental update migration is idempotent
|
|
8
|
+
# with monolithic install migration.
|
|
9
|
+
return if connection.column_exists?(:good_jobs, :labels)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
add_column :good_jobs, :labels, :text, array: true
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/generators/good_job/templates/update/migrations/09_create_good_job_labels_index.rb.erb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateGoodJobLabelsIndex < ActiveRecord::Migration<%= migration_version %>
|
|
4
|
+
disable_ddl_transaction!
|
|
5
|
+
|
|
6
|
+
def change
|
|
7
|
+
reversible do |dir|
|
|
8
|
+
dir.up do
|
|
9
|
+
unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_labels)
|
|
10
|
+
add_index :good_jobs, :labels, using: :gin, where: "(labels IS NOT NULL)",
|
|
11
|
+
name: :index_good_jobs_on_labels, algorithm: :concurrently
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
dir.down do
|
|
16
|
+
if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_labels)
|
|
17
|
+
remove_index :good_jobs, name: :index_good_jobs_on_labels
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/generators/good_job/templates/update/migrations/10_remove_good_job_active_id_index.rb.erb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class RemoveGoodJobActiveIdIndex < ActiveRecord::Migration<%= migration_version %>
|
|
4
|
+
disable_ddl_transaction!
|
|
5
|
+
|
|
6
|
+
def change
|
|
7
|
+
reversible do |dir|
|
|
8
|
+
dir.up do
|
|
9
|
+
if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id)
|
|
10
|
+
remove_index :good_jobs, name: :index_good_jobs_on_active_job_id
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
dir.down do
|
|
15
|
+
unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id)
|
|
16
|
+
add_index :good_jobs, :active_job_id, name: :index_good_jobs_on_active_job_id
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GoodJob
|
|
4
|
+
module ActiveJobExtensions
|
|
5
|
+
module Labels
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
module Prepends
|
|
9
|
+
def initialize(*arguments)
|
|
10
|
+
super
|
|
11
|
+
self.good_job_labels = Array(self.class.good_job_labels)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def enqueue(options = {})
|
|
15
|
+
self.good_job_labels = Array(options[:good_job_labels]) if options.key?(:good_job_labels)
|
|
16
|
+
super
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def deserialize(job_data)
|
|
20
|
+
super
|
|
21
|
+
self.good_job_labels = job_data.delete("good_job_labels")&.dup || []
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
included do
|
|
26
|
+
prepend Prepends
|
|
27
|
+
class_attribute :good_job_labels, instance_accessor: false, instance_predicate: false, default: []
|
|
28
|
+
attr_accessor :good_job_labels
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/good_job/version.rb
CHANGED
data/lib/good_job.rb
CHANGED
|
@@ -12,6 +12,7 @@ require "good_job/active_job_extensions/batches"
|
|
|
12
12
|
require "good_job/active_job_extensions/concurrency"
|
|
13
13
|
require "good_job/interrupt_error"
|
|
14
14
|
require "good_job/active_job_extensions/interrupt_errors"
|
|
15
|
+
require "good_job/active_job_extensions/labels"
|
|
15
16
|
require "good_job/active_job_extensions/notify_options"
|
|
16
17
|
|
|
17
18
|
require "good_job/assignable_connection"
|
|
@@ -22,7 +23,7 @@ require "good_job/cleanup_tracker"
|
|
|
22
23
|
require "good_job/cli"
|
|
23
24
|
require "good_job/configuration"
|
|
24
25
|
require "good_job/cron_manager"
|
|
25
|
-
require
|
|
26
|
+
require "good_job/current_thread"
|
|
26
27
|
require "good_job/daemon"
|
|
27
28
|
require "good_job/dependencies"
|
|
28
29
|
require "good_job/job_performer"
|
|
@@ -272,7 +273,7 @@ module GoodJob
|
|
|
272
273
|
def self.migrated?
|
|
273
274
|
# Always update with the most recent migration check
|
|
274
275
|
GoodJob::Execution.reset_column_information
|
|
275
|
-
GoodJob::Execution.
|
|
276
|
+
GoodJob::Execution.active_job_id_index_removal_migrated?
|
|
276
277
|
end
|
|
277
278
|
|
|
278
279
|
ActiveSupport.run_load_hooks(:good_job, self)
|
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: 3.
|
|
4
|
+
version: 3.22.0
|
|
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: 2024-01-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activejob
|
|
@@ -307,6 +307,7 @@ files:
|
|
|
307
307
|
- app/views/good_job/shared/_filter.erb
|
|
308
308
|
- app/views/good_job/shared/_footer.erb
|
|
309
309
|
- app/views/good_job/shared/_navbar.erb
|
|
310
|
+
- app/views/good_job/shared/_secondary_navbar.erb
|
|
310
311
|
- app/views/good_job/shared/icons/_arrow_clockwise.html.erb
|
|
311
312
|
- app/views/good_job/shared/icons/_check.html.erb
|
|
312
313
|
- app/views/good_job/shared/icons/_circle_half.html.erb
|
|
@@ -345,11 +346,15 @@ files:
|
|
|
345
346
|
- lib/generators/good_job/templates/update/migrations/05_create_good_job_executions.rb.erb
|
|
346
347
|
- lib/generators/good_job/templates/update/migrations/06_create_good_jobs_error_event.rb.erb
|
|
347
348
|
- lib/generators/good_job/templates/update/migrations/07_recreate_good_job_cron_indexes_with_conditional.rb.erb
|
|
349
|
+
- lib/generators/good_job/templates/update/migrations/08_create_good_job_labels.rb.erb
|
|
350
|
+
- lib/generators/good_job/templates/update/migrations/09_create_good_job_labels_index.rb.erb
|
|
351
|
+
- lib/generators/good_job/templates/update/migrations/10_remove_good_job_active_id_index.rb.erb
|
|
348
352
|
- lib/generators/good_job/update_generator.rb
|
|
349
353
|
- lib/good_job.rb
|
|
350
354
|
- lib/good_job/active_job_extensions/batches.rb
|
|
351
355
|
- lib/good_job/active_job_extensions/concurrency.rb
|
|
352
356
|
- lib/good_job/active_job_extensions/interrupt_errors.rb
|
|
357
|
+
- lib/good_job/active_job_extensions/labels.rb
|
|
353
358
|
- lib/good_job/active_job_extensions/notify_options.rb
|
|
354
359
|
- lib/good_job/adapter.rb
|
|
355
360
|
- lib/good_job/assignable_connection.rb
|