good_job 3.21.5 → 3.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +67 -1
  3. data/README.md +144 -41
  4. data/app/controllers/good_job/jobs_controller.rb +1 -1
  5. data/app/helpers/good_job/application_helper.rb +3 -2
  6. data/app/models/concerns/good_job/filterable.rb +1 -1
  7. data/app/models/good_job/base_execution.rb +33 -4
  8. data/app/models/good_job/batch.rb +1 -1
  9. data/app/models/good_job/execution.rb +11 -4
  10. data/app/models/good_job/job.rb +4 -4
  11. data/app/views/good_job/shared/_filter.erb +2 -2
  12. data/app/views/good_job/shared/_footer.erb +1 -9
  13. data/app/views/good_job/shared/_navbar.erb +22 -4
  14. data/app/views/good_job/shared/_secondary_navbar.erb +11 -0
  15. data/app/views/good_job/shared/icons/_globe.html.erb +3 -0
  16. data/app/views/layouts/good_job/application.html.erb +34 -39
  17. data/config/locales/de.yml +3 -3
  18. data/config/locales/en.yml +3 -3
  19. data/config/locales/es.yml +3 -3
  20. data/config/locales/fr.yml +3 -3
  21. data/config/locales/ja.yml +3 -3
  22. data/config/locales/ko.yml +243 -0
  23. data/config/locales/nl.yml +3 -3
  24. data/config/locales/ru.yml +76 -78
  25. data/config/locales/tr.yml +3 -3
  26. data/config/locales/uk.yml +3 -3
  27. data/lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb +4 -1
  28. data/lib/generators/good_job/templates/update/migrations/08_create_good_job_labels.rb.erb +15 -0
  29. data/lib/generators/good_job/templates/update/migrations/09_create_good_job_labels_index.rb.erb +22 -0
  30. data/lib/generators/good_job/templates/update/migrations/10_remove_good_job_active_id_index.rb.erb +21 -0
  31. data/lib/generators/good_job/templates/update/migrations/11_create_index_good_job_jobs_for_candidate_lookup.rb.erb +19 -0
  32. data/lib/good_job/active_job_extensions/labels.rb +32 -0
  33. data/lib/good_job/adapter.rb +2 -2
  34. data/lib/good_job/cli.rb +5 -2
  35. data/lib/good_job/configuration.rb +18 -2
  36. data/lib/good_job/probe_server/healthcheck_middleware.rb +27 -0
  37. data/lib/good_job/probe_server/not_found_app.rb +11 -0
  38. data/lib/good_job/probe_server/simple_handler.rb +83 -0
  39. data/lib/good_job/probe_server/webrick_handler.rb +28 -0
  40. data/lib/good_job/probe_server.rb +21 -16
  41. data/lib/good_job/version.rb +1 -1
  42. data/lib/good_job.rb +8 -4
  43. metadata +28 -3
  44. data/lib/good_job/http_server.rb +0 -77
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa13b9d970c63760bc8264906c0aeccf1f71f0b6e678338cca21778956fdba0a
4
- data.tar.gz: cd4d0e5be595b266396a2ffa0d9da0955940f1afe7639a2456b9a8f67e9d205b
3
+ metadata.gz: c4b22e7bf97af388b110d33742f0e1ce762570a509c85b8abd8425d668f691c4
4
+ data.tar.gz: 4f5ab8ec5fef5a2996f917851cea61a967fc73ac08afcd61edc248a5f121606e
5
5
  SHA512:
6
- metadata.gz: '0871dcec35bfe62dbc59f07e81aa048cd04300316e859080a7f61f1666e61a1641a52ce76e6d827d2bf6e7524dd3893cacda66d94fb7ec994d88ae2e7b616ead'
7
- data.tar.gz: 7171bf22d85558b2f48bbecc80fbe5a57cea331be996b6324e266bc1e8a1da9a3a13f9ab191d5dac167797be5e2b64c0a7bb9ebb05e4937b2946de9bafc17193
6
+ metadata.gz: b20eabb8bd33b6c1223a8d60244a75681c939193ba22904531cf4c5d4f92ca2266665e2feb60dd7ee9db8b6ba017d3980bd789b4d90c7c9806b5db42ce08bdb9
7
+ data.tar.gz: da0c451f930fb9226a74ce6d03aea3dd5bdb61cfff4e00d3e9f0664032105e357eea653d86c79759f3b67a999e59306f4cc33f9684d7edcdea48fee322ad2e27
data/CHANGELOG.md CHANGED
@@ -1,5 +1,72 @@
1
1
  # Changelog
2
2
 
3
+ ## [v3.23.0](https://github.com/bensheldon/good_job/tree/v3.23.0) (2024-01-23)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.22.0...v3.23.0)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Add environment label to navbar [\#1206](https://github.com/bensheldon/good_job/pull/1206) ([sparshalc](https://github.com/sparshalc))
10
+ - Make health probe server more general purpose [\#1079](https://github.com/bensheldon/good_job/pull/1079) ([jklina](https://github.com/jklina))
11
+
12
+ **Fixed bugs:**
13
+
14
+ - Use Rails executor instead of reloader when wrapping inline execution [\#1225](https://github.com/bensheldon/good_job/pull/1225) ([bensheldon](https://github.com/bensheldon))
15
+ - Add an index to better support `smaller_number_is_higher_priority` [\#1213](https://github.com/bensheldon/good_job/pull/1213) ([mkrfowler](https://github.com/mkrfowler))
16
+ - Fix discard job with nonexistent job class [\#1211](https://github.com/bensheldon/good_job/pull/1211) ([yenshirak](https://github.com/yenshirak))
17
+ - Fix: Interacting with input field should pause the live poll [\#1210](https://github.com/bensheldon/good_job/pull/1210) ([sparshalc](https://github.com/sparshalc))
18
+
19
+ **Closed issues:**
20
+
21
+ - can't write unknown attribute `active_job_id` [\#1216](https://github.com/bensheldon/good_job/issues/1216)
22
+ - Regression: use of Rails reloader causing mixed constants during seeding [\#1215](https://github.com/bensheldon/good_job/issues/1215)
23
+ - Production worker doesn't show any processes [\#1214](https://github.com/bensheldon/good_job/issues/1214)
24
+ - Clarify required async mode DB pool size [\#1209](https://github.com/bensheldon/good_job/issues/1209)
25
+ - Mac forking exception when using Spring [\#1115](https://github.com/bensheldon/good_job/issues/1115)
26
+ - Jobs should have labels [\#1095](https://github.com/bensheldon/good_job/issues/1095)
27
+ - Set up Dependabot grouped updates [\#1062](https://github.com/bensheldon/good_job/issues/1062)
28
+ - Fix documentation to always include space in "Active Job", "Active Record", etc. [\#1048](https://github.com/bensheldon/good_job/issues/1048)
29
+
30
+ **Merged pull requests:**
31
+
32
+ - Bump actions/cache from 3 to 4 [\#1223](https://github.com/bensheldon/good_job/pull/1223) ([dependabot[bot]](https://github.com/apps/dependabot))
33
+ - Update README, add poll\_interval defaults/recommendations [\#1220](https://github.com/bensheldon/good_job/pull/1220) ([andynu](https://github.com/andynu))
34
+ - Update Russian translation [\#1219](https://github.com/bensheldon/good_job/pull/1219) ([alec-c4](https://github.com/alec-c4))
35
+ - Add Korean translation \(ko\) [\#1212](https://github.com/bensheldon/good_job/pull/1212) ([hahwul](https://github.com/hahwul))
36
+ - Fix default poll interval in documentation [\#1208](https://github.com/bensheldon/good_job/pull/1208) ([yenshirak](https://github.com/yenshirak))
37
+
38
+ ## [v3.22.0](https://github.com/bensheldon/good_job/tree/v3.22.0) (2024-01-03)
39
+
40
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.21.5...v3.22.0)
41
+
42
+ **Implemented enhancements:**
43
+
44
+ - Add "updated at" info in secondary top navbar [\#1204](https://github.com/bensheldon/good_job/pull/1204) ([sparshalc](https://github.com/sparshalc))
45
+ - Re-add footer with GoodJob version number [\#1201](https://github.com/bensheldon/good_job/pull/1201) ([Pauloparakleto](https://github.com/Pauloparakleto))
46
+ - Add Active Job extension for Labels [\#1188](https://github.com/bensheldon/good_job/pull/1188) ([bensheldon](https://github.com/bensheldon))
47
+
48
+ **Closed issues:**
49
+
50
+ - Limiting by executed jobs count by period [\#1198](https://github.com/bensheldon/good_job/issues/1198)
51
+ - Cron jobs processing in async mode [\#1196](https://github.com/bensheldon/good_job/issues/1196)
52
+ - Dashboard Missing Translation? [\#1192](https://github.com/bensheldon/good_job/issues/1192)
53
+ - Show last update on top nav bar [\#1183](https://github.com/bensheldon/good_job/issues/1183)
54
+ - Wrong quoting of the query to spot new jobs? [\#1179](https://github.com/bensheldon/good_job/issues/1179)
55
+ - \[Possible bug\] good\_job does not honour the wait parameter on retry\_on [\#1174](https://github.com/bensheldon/good_job/issues/1174)
56
+ - 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)
57
+
58
+ **Merged pull requests:**
59
+
60
+ - Bump the bundler-dependencies group with 3 updates [\#1202](https://github.com/bensheldon/good_job/pull/1202) ([dependabot[bot]](https://github.com/apps/dependabot))
61
+ - Remove duplicated intro sentence in README [\#1195](https://github.com/bensheldon/good_job/pull/1195) ([benoittgt](https://github.com/benoittgt))
62
+ - Fix namespace for `InterruptError` in README [\#1193](https://github.com/bensheldon/good_job/pull/1193) ([padde](https://github.com/padde))
63
+ - Bump github/codeql-action from 2 to 3 [\#1191](https://github.com/bensheldon/good_job/pull/1191) ([dependabot[bot]](https://github.com/apps/dependabot))
64
+ - Bump actions/upload-artifact from 3 to 4 [\#1190](https://github.com/bensheldon/good_job/pull/1190) ([dependabot[bot]](https://github.com/apps/dependabot))
65
+ - Lock RubyGems version for Ruby \< 3.0 in CI [\#1189](https://github.com/bensheldon/good_job/pull/1189) ([bensheldon](https://github.com/bensheldon))
66
+ - Active Record and Active Job name formatting [\#1182](https://github.com/bensheldon/good_job/pull/1182) ([andyatkinson](https://github.com/andyatkinson))
67
+ - Remove redundant `good_jobs.active_job_id` index [\#1181](https://github.com/bensheldon/good_job/pull/1181) ([andyatkinson](https://github.com/andyatkinson))
68
+ - Add missing word in readme [\#1177](https://github.com/bensheldon/good_job/pull/1177) ([Earlopain](https://github.com/Earlopain))
69
+
3
70
  ## [v3.21.5](https://github.com/bensheldon/good_job/tree/v3.21.5) (2023-12-12)
4
71
 
5
72
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.21.4...v3.21.5)
@@ -1571,7 +1638,6 @@
1571
1638
  **Fixed bugs:**
1572
1639
 
1573
1640
  - `ActionMailer::MailDeliveryJob` executing twice [\#329](https://github.com/bensheldon/good_job/issues/329)
1574
- - Email job breaks dashboard [\#313](https://github.com/bensheldon/good_job/issues/313)
1575
1641
 
1576
1642
  **Closed issues:**
1577
1643
 
data/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
  [![Test Status](https://github.com/bensheldon/good_job/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/bensheldon/good_job/actions/workflows/test.yml?query=branch%3Amain)
5
5
  [![Ruby Toolbox](https://img.shields.io/badge/dynamic/json?color=blue&label=Ruby%20Toolbox&query=%24.projects%5B0%5D.score&url=https%3A%2F%2Fwww.ruby-toolbox.com%2Fapi%2Fprojects%2Fcompare%2Fgood_job&logo=data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgZGF0YS1wcmVmaXg9ImZhcyIgZGF0YS1pY29uPSJmbGFzayIgY2xhc3M9InN2Zy1pbmxpbmUtLWZhIGZhLWZsYXNrIGZhLXctMTQiIHJvbGU9ImltZyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDQ4IDUxMiI+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik00MzcuMiA0MDMuNUwzMjAgMjE1VjY0aDhjMTMuMyAwIDI0LTEwLjcgMjQtMjRWMjRjMC0xMy4zLTEwLjctMjQtMjQtMjRIMTIwYy0xMy4zIDAtMjQgMTAuNy0yNCAyNHYxNmMwIDEzLjMgMTAuNyAyNCAyNCAyNGg4djE1MUwxMC44IDQwMy41Qy0xOC41IDQ1MC42IDE1LjMgNTEyIDcwLjkgNTEyaDMwNi4yYzU1LjcgMCA4OS40LTYxLjUgNjAuMS0xMDguNXpNMTM3LjkgMzIwbDQ4LjItNzcuNmMzLjctNS4yIDUuOC0xMS42IDUuOC0xOC40VjY0aDY0djE2MGMwIDYuOSAyLjIgMTMuMiA1LjggMTguNGw0OC4yIDc3LjZoLTE3MnoiPjwvcGF0aD48L3N2Zz4=)](https://www.ruby-toolbox.com/projects/good_job)
6
6
 
7
- GoodJob is a multithreaded, Postgres-based, ActiveJob backend for Ruby on Rails.
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, ActiveJob, and Postgres to be simple and performant for most workloads.**
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 ActiveJob.** Complete support for [async, queues, delays, priorities, timeouts, and retries](https://edgeguides.rubyonrails.org/active_job_basics.html) with near-zero configuration.
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
- - [ActionMailer retries](#actionmailer-retries)
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 ActiveJob backend](#migrate-to-goodjob-from-a-different-activejob-backend)
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 ActiveJob adapter:
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 ActiveJob features:
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
@@ -177,18 +177,19 @@ Usage:
177
177
  good_job start
178
178
 
179
179
  Options:
180
- [--queues=QUEUE_LIST] # Queues or pools to work from. (env var: GOOD_JOB_QUEUES, default: *)
181
- [--max-threads=COUNT] # Default number of threads per pool to use for working jobs. (env var: GOOD_JOB_MAX_THREADS, default: 5)
182
- [--poll-interval=SECONDS] # Interval between polls for available jobs in seconds (env var: GOOD_JOB_POLL_INTERVAL, default: 1)
183
- [--max-cache=COUNT] # Maximum number of scheduled jobs to cache in memory (env var: GOOD_JOB_MAX_CACHE, default: 10000)
184
- [--shutdown-timeout=SECONDS] # Number of seconds to wait for jobs to finish when shutting down before stopping the thread. (env var: GOOD_JOB_SHUTDOWN_TIMEOUT, default: -1 (forever))
185
- [--enable-cron] # Whether to run cron process (default: false)
186
- [--enable-listen-notify] # Whether to enqueue and read jobs with Postgres LISTEN/NOTIFY (default: true)
187
- [--idle-timeout=SECONDS] # Exit process when no jobs have been performed for this many seconds (env var: GOOD_JOB_IDLE_TIMEOUT, default: nil)
188
- [--daemonize] # Run as a background daemon (default: false)
189
- [--pidfile=PIDFILE] # Path to write daemonized Process ID (env var: GOOD_JOB_PIDFILE, default: tmp/pids/good_job.pid)
190
- [--probe-port=PORT] # Port for http health check (env var: GOOD_JOB_PROBE_PORT, default: nil)
191
- [--queue-select-limit=COUNT] # The number of queued jobs to select when polling for a job to run. (env var: GOOD_JOB_QUEUE_SELECT_LIMIT, default: nil)"
180
+ [--queues=QUEUE_LIST] # Queues or pools to work from. (env var: GOOD_JOB_QUEUES, default: *)
181
+ [--max-threads=COUNT] # Default number of threads per pool to use for working jobs. (env var: GOOD_JOB_MAX_THREADS, default: 5)
182
+ [--poll-interval=SECONDS] # Interval between polls for available jobs in seconds (env var: GOOD_JOB_POLL_INTERVAL, default: 10)
183
+ [--max-cache=COUNT] # Maximum number of scheduled jobs to cache in memory (env var: GOOD_JOB_MAX_CACHE, default: 10000)
184
+ [--shutdown-timeout=SECONDS] # Number of seconds to wait for jobs to finish when shutting down before stopping the thread. (env var: GOOD_JOB_SHUTDOWN_TIMEOUT, default: -1 (forever))
185
+ [--enable-cron] # Whether to run cron process (default: false)
186
+ [--enable-listen-notify] # Whether to enqueue and read jobs with Postgres LISTEN/NOTIFY (default: true)
187
+ [--idle-timeout=SECONDS] # Exit process when no jobs have been performed for this many seconds (env var: GOOD_JOB_IDLE_TIMEOUT, default: nil)
188
+ [--daemonize] # Run as a background daemon (default: false)
189
+ [--pidfile=PIDFILE] # Path to write daemonized Process ID (env var: GOOD_JOB_PIDFILE, default: tmp/pids/good_job.pid)
190
+ [--probe-port=PORT] # Port for http health check (env var: GOOD_JOB_PROBE_PORT, default: nil)
191
+ [--probe-handler=PROBE_HANDLER] # Use 'webrick' to use WEBrick to handle probe server requests which is Rack compliant, otherwise default server that is not Rack compliant is used.
192
+ [--queue-select-limit=COUNT] # The number of queued jobs to select when polling for a job to run. (env var: GOOD_JOB_QUEUE_SELECT_LIMIT, default: nil)"
192
193
 
193
194
  Executes queued jobs.
194
195
 
@@ -222,7 +223,7 @@ and this command is not required to be used.
222
223
 
223
224
  ### Configuration options
224
225
 
225
- ActiveJob configuration depends on where the code is placed:
226
+ Active Job configuration depends on where the code is placed:
226
227
 
227
228
  - `config.active_job.queue_adapter = :good_job` within `config/application.rb` or `config/environments/*.rb`.
228
229
  - `ActiveJob::Base.queue_adapter = :good_job` within an initializer (e.g. `config/initializers/active_job.rb`).
@@ -280,6 +281,10 @@ Available configuration options are:
280
281
  - `queues` (string) sets queues or pools to execute jobs. You can also set this with the environment variable `GOOD_JOB_QUEUES`.
281
282
  - `max_threads` (integer) sets the default number of threads per pool to use for working jobs. You can also set this with the environment variable `GOOD_JOB_MAX_THREADS`.
282
283
  - `poll_interval` (integer) 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`. A poll interval of `-1` disables polling completely.
284
+ - production default: 10 seconds (in case of a LISTEN/NOTIFY blip)
285
+ - development default: -1, disabled (because the application is likely being restarted often and won't be running unobserved). You can enable it by setting a `poll_interval`.
286
+ - LISTEN/NOTIFY is enabled in both production and development, so polling is not strictly necessary.
287
+ - If LISTEN/NOTIFY is disabled, you should configure polling for future-scheduled jobs. GoodJob will cache in memory the scheduled time and check for executable jobs at that time. If the cache is exceeded (10k scheduled jobs by default) that's another reason to poll just in case.
283
288
  - `max_cache` (integer) sets the maximum number of scheduled jobs that will be stored in memory to reduce execution latency when also polling for scheduled jobs. Caching 10,000 scheduled jobs uses approximately 20MB of memory. You can also set this with the environment variable `GOOD_JOB_MAX_CACHE`.
284
289
  - `shutdown_timeout` (integer) number of seconds to wait for jobs to finish when shutting down before stopping the thread. Defaults to forever: `-1`. You can also set this with the environment variable `GOOD_JOB_SHUTDOWN_TIMEOUT`.
285
290
  - `enable_cron` (boolean) whether to run cron process. Defaults to `false`. You can also set this with the environment variable `GOOD_JOB_ENABLE_CRON`.
@@ -300,6 +305,18 @@ Available configuration options are:
300
305
  config.good_job.on_thread_error = -> (exception) { Rails.error.report(exception) }
301
306
  ```
302
307
 
308
+ - `probe_server_app` (Rack application) allows you to specify a Rack application to be used for the probe server. Defaults to `nil` which uses the default probe server. Example:
309
+
310
+ ```ruby
311
+ config.good_job.probe_app = -> (env) { [200, {}, ["OK"]] }
312
+ ```
313
+
314
+ - `probe_handler` (string) allows you to use WEBrick, a fully Rack compliant webserver instead of the simple default server. **Note:** You'll need to ensure WEBrick is in your load path as GoodJob doesn't have WEBrick as a dependency. Example:
315
+
316
+ ```ruby
317
+ config.good_job.probe_handler = 'webrick'
318
+ ```
319
+
303
320
  By default, GoodJob configures the following execution modes per environment:
304
321
 
305
322
  ```ruby
@@ -321,7 +338,7 @@ config.good_job.execution_mode = :external
321
338
 
322
339
  Good Job’s general behavior can also be configured via attributes directly on the `GoodJob` module:
323
340
 
324
- - **`GoodJob.configure_active_record { ... }`** Inject Active Record configuration into GoodJob's base model, for example, 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. Example:
341
+ - **`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
342
 
326
343
  ```ruby
327
344
  # config/initializers/good_job.rb
@@ -331,7 +348,7 @@ Good Job’s general behavior can also be configured via attributes directly on
331
348
  end
332
349
  ```
333
350
 
334
- - **`GoodJob.active_record_parent_class`** (string) Alternatively, modify the ActiveRecord 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 ActiveRecord._
351
+ - **`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
352
 
336
353
  You’ll generally want to configure these in `config/initializers/good_job.rb`, like so:
337
354
 
@@ -438,9 +455,34 @@ The Dashboard can be set to automatically refresh by checking "Live Poll" in the
438
455
 
439
456
  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
457
 
458
+ ### Labelled jobs
459
+
460
+ 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.
461
+
462
+ ```ruby
463
+ class ApplicationRecord < ActiveJob::Base
464
+ include GoodJob::ActiveJobExtensions::Labels
465
+ end
466
+
467
+ # Add a default label to every job within the class
468
+ class WelcomeJob < ApplicationRecord
469
+ self.good_job_labels = ["email"]
470
+
471
+ def perform
472
+ # Labels can be inspected from within the job
473
+ puts good_job_labels # => ["email"]
474
+ end
475
+ end
476
+
477
+ # Or add to individual jobs when enqueued
478
+ WelcomeJob.set(good_job_labels: ["email"]).perform_later
479
+ ```
480
+
481
+ Labels can be used to search jobs in the Dashboard. For example, to find all jobs labeled `email`, search for `email`.
482
+
441
483
  ### Concurrency controls
442
484
 
443
- 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 unnecessary jobs from being enqueued, or race conditions when performing, for example when interacting with 3rd-party APIs.
485
+ 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
486
 
445
487
  ```ruby
446
488
  class MyJob < ApplicationJob
@@ -469,7 +511,7 @@ class MyJob < ApplicationJob
469
511
 
470
512
  # A unique key to be globally locked against.
471
513
  # 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 ActiveJob's `arguments` method
514
+ # Note: Arguments passed to #perform_later can be accessed through Active Job's `arguments` method
473
515
  # which is an array containing positional arguments and, optionally, a kwarg hash.
474
516
  key: -> { "MyJob-#{arguments.first}-#{arguments.last[:version]}" } # MyJob.perform_later("Alice", version: 'v2') => "MyJob-Alice-v2"
475
517
  )
@@ -549,11 +591,11 @@ active_jobs = GoodJob::Bulk.enqueue do
549
591
  # If an exception is raised within this block, no jobs will be inserted.
550
592
  end
551
593
 
552
- # All ActiveJob instances are returned from GoodJob::Bulk.enqueue.
594
+ # All Active Job instances are returned from GoodJob::Bulk.enqueue.
553
595
  # Jobs that have been successfully enqueued have a `provider_job_id` set.
554
596
  active_jobs.all?(&:provider_job_id)
555
597
 
556
- # Bulk enqueue ActiveJob instances directly without using `.perform_later`:
598
+ # Bulk enqueue Active Job instances directly without using `.perform_later`:
557
599
  GoodJob::Bulk.enqueue(MyJob.new, AnotherJob.new)
558
600
  ```
559
601
 
@@ -737,7 +779,7 @@ GoodJob follows semantic versioning, though updates may be encouraged through de
737
779
 
738
780
  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
781
 
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.
782
+ 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
783
 
742
784
  To perform upgrades to the GoodJob database tables:
743
785
 
@@ -791,7 +833,7 @@ Notable changes:
791
833
  - Renames `:async_server` execution mode to `:async`; renames prior `:async` execution mode to `:async_all`.
792
834
  - Sets default Development environment's execution mode to `:async` with disabled polling.
793
835
  - Excludes performing jobs from `enqueue_limit`'s count in `GoodJob::ActiveJobExtensions::Concurrency`.
794
- - Triggers `GoodJob.on_thread_error` for unhandled ActiveJob exceptions.
836
+ - Triggers `GoodJob.on_thread_error` for unhandled Active Job exceptions.
795
837
  - Renames `GoodJob.reperform_jobs_on_standard_error` accessor to `GoodJob.retry_on_unhandled_error`.
796
838
  - Renames `GoodJob::Adapter.shutdown(wait:)` argument to `GoodJob::Adapter.shutdown(timeout:)`.
797
839
  - Changes Advisory Lock key format from `good_jobs[ROW_ID]` to `good_jobs-[ACTIVE_JOB_ID]`.
@@ -801,11 +843,11 @@ Notable changes:
801
843
 
802
844
  ### Exceptions, retries, and reliability
803
845
 
804
- GoodJob guarantees that a completely-performed job will run once and only once. GoodJob fully supports ActiveJob's built-in functionality for error handling, retries and timeouts.
846
+ 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
847
 
806
848
  #### Exceptions
807
849
 
808
- ActiveJob 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.
850
+ 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
851
 
810
852
  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
853
 
@@ -816,9 +858,9 @@ GoodJob.on_thread_error = -> (exception) { Rails.error.report(exception) }
816
858
 
817
859
  #### Retries
818
860
 
819
- By default, GoodJob relies on ActiveJob's retry functionality.
861
+ By default, GoodJob relies on Active Job's retry functionality.
820
862
 
821
- ActiveJob can be configured to retry an infinite number of times, with a polynomial backoff. Using ActiveJob's `retry_on` prevents exceptions from reaching GoodJob:
863
+ 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
864
 
823
865
  ```ruby
824
866
  class ApplicationJob < ActiveJob::Base
@@ -860,7 +902,7 @@ end
860
902
 
861
903
  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
904
 
863
- #### ActionMailer retries
905
+ #### Action Mailer retries
864
906
 
865
907
  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
908
 
@@ -886,16 +928,16 @@ might also be configured to use (deprecated now) `ActionMailer::DeliveryJob`.
886
928
 
887
929
  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
930
 
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 ActiveJob's `retry_on` and `discard_on` to control the behavior of the job.
931
+ 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
932
 
891
933
  ```ruby
892
934
  class MyJob < ApplicationJob
893
935
  # The extension must be included before other extensions
894
936
  include GoodJob::ActiveJobExtensions::InterruptErrors
895
937
  # Discard the job if it is interrupted
896
- discard_on InterruptError
938
+ discard_on GoodJob::InterruptError
897
939
  # Retry the job if it is interrupted
898
- retry_on InterruptError, wait: 0, attempts: Float::INFINITY
940
+ retry_on GoodJob::InterruptError, wait: 0, attempts: Float::INFINITY
899
941
  end
900
942
  ```
901
943
 
@@ -1176,9 +1218,9 @@ Depending on your application configuration, you may need to take additional ste
1176
1218
 
1177
1219
  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
1220
 
1179
- ### Migrate to GoodJob from a different ActiveJob backend
1221
+ ### Migrate to GoodJob from a different Active Job backend
1180
1222
 
1181
- If your application is already using an ActiveJob backend, you will need to install GoodJob to enqueue and perform newly created jobs _and_ finish performing pre-existing jobs on the previous backend.
1223
+ 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
1224
 
1183
1225
  1. Enqueue newly created jobs on GoodJob either entirely by setting `ActiveJob::Base.queue_adapter = :good_job` or progressively via individual job classes:
1184
1226
 
@@ -1198,7 +1240,7 @@ If your application is already using an ActiveJob backend, you will need to inst
1198
1240
  worker: bundle exec que ./config/environment.rb & bundle exec good_job & wait -n
1199
1241
  ```
1200
1242
 
1201
- 1. Once you are confident that no unperformed jobs remain in the previous ActiveJob backend, code and configuration for that backend can be completely removed.
1243
+ 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
1244
 
1203
1245
  ### Monitor and preserve worked jobs
1204
1246
 
@@ -1271,7 +1313,7 @@ A workaround to this limitation is to make a direct database connection availabl
1271
1313
  url: postgres://database_host/my_database
1272
1314
  ```
1273
1315
 
1274
- 1. Create a new ActiveRecord base class that uses the direct database connection
1316
+ 1. Create a new Active Record base class that uses the direct database connection
1275
1317
 
1276
1318
  ```ruby
1277
1319
  # app/models/application_direct_record.rb
@@ -1282,7 +1324,7 @@ A workaround to this limitation is to make a direct database connection availabl
1282
1324
  end
1283
1325
  ```
1284
1326
 
1285
- 1. Configure GoodJob to use the newly created ActiveRecord base class:
1327
+ 1. Configure GoodJob to use the newly created Active Record base class:
1286
1328
 
1287
1329
  ```ruby
1288
1330
  # config/initializers/good_job.rb
@@ -1292,6 +1334,8 @@ A workaround to this limitation is to make a direct database connection availabl
1292
1334
 
1293
1335
  ### CLI HTTP health check probes
1294
1336
 
1337
+ #### Default configuration
1338
+
1295
1339
  GoodJob's CLI offers an http health check probe to better manage process lifecycle in containerized environments like Kubernetes:
1296
1340
 
1297
1341
  ```bash
@@ -1345,6 +1389,65 @@ spec:
1345
1389
  periodSeconds: 10
1346
1390
  ```
1347
1391
 
1392
+ #### Custom configuration
1393
+
1394
+ The CLI health check probe server can be customized to serve additional information. Two things to note when customizing the probe server:
1395
+
1396
+ - By default, the probe server uses a homespun single thread, blocking server so your custom app should be very simple and lightly used and could affect job performance.
1397
+ - The default probe server is not fully Rack compliant. Rack specifies various mandatory fields and some Rack apps assume those fields exist. If you do need to use a Rack app that depends on being fully Rack compliant, you can configure GoodJob to [use WEBrick as the server](#using-webrick)
1398
+
1399
+ To customize the probe server, set `config.good_job.probe_app` to a Rack app or a Rack builder:
1400
+
1401
+ ```ruby
1402
+ # config/initializers/good_job.rb OR config/application.rb OR config/environments/{RAILS_ENV}.rb
1403
+
1404
+ Rails.application.configure do
1405
+ config.good_job.probe_app = Rack::Builder.new do
1406
+ # Add your custom middleware
1407
+ use Custom::AuthorizationMiddleware
1408
+ use Custom::PrometheusExporter
1409
+
1410
+ # This is the default middleware
1411
+ use GoodJob::ProbeServer::HealthcheckMiddleware
1412
+ run GoodJob::ProbeServer::NotFoundApp # will return 404 for all other requests
1413
+ end
1414
+ end
1415
+ ```
1416
+
1417
+ ##### Using WEBrick
1418
+
1419
+ If your custom app requires a fully Rack compliant server, you can configure GoodJob to use WEBrick as the server:
1420
+
1421
+ ```ruby
1422
+ # config/initializers/good_job.rb OR config/application.rb OR config/environments/{RAILS_ENV}.rb
1423
+
1424
+ Rails.application.configure do
1425
+ config.good_job.probe_handler = :webrick
1426
+ end
1427
+
1428
+ ```
1429
+
1430
+ You can also enable WEBrick through the command line:
1431
+
1432
+ ```bash
1433
+ good_job start --probe-handler=webrick
1434
+ ```
1435
+
1436
+ or via an environment variable:
1437
+
1438
+ ```bash
1439
+ GOOD_JOB_PROBE_HANDLER=webrick good_job start
1440
+ ```
1441
+
1442
+ Note that GoodJob doesn't include WEBrick as a dependency, so you'll need to add it to your Gemfile:
1443
+
1444
+ ```ruby
1445
+ # Gemfile
1446
+ gem 'webrick'
1447
+ ```
1448
+
1449
+ If WEBrick is configured to be used, but the dependency is not found, GoodJob will log a warning and fallback to the default probe server.
1450
+
1348
1451
  ## Contribute
1349
1452
 
1350
1453
  <!-- Please keep this section in sync with CONTRIBUTING.md -->
@@ -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
- "ActiveJob Queue Adapter must be GoodJob."
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
@@ -53,10 +53,11 @@ module GoodJob
53
53
  content_tag :span, icon, **options
54
54
  end
55
55
 
56
- def render_icon(name)
56
+ def render_icon(name, **options)
57
57
  # workaround to render svg icons without all of the log messages
58
58
  partial = lookup_context.find_template("good_job/shared/icons/#{name}", [], true)
59
- partial.render(self, {})
59
+ options[:class] = Array(options[:class]).join(" ")
60
+ partial.render(self, { class: options[:class] })
60
61
  end
61
62
 
62
63
  def translate_hash(key, **options)
@@ -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', serialized_params) || to_tsvector('english', id::text) || to_tsvector('english', COALESCE(error, '')::text))"
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
- # ActiveRecord model to share behavior between {Job} and {Execution} models
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,34 @@ 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
80
+
81
+ def candidate_lookup_index_migrated?
82
+ return true if connection.index_name_exists?(:good_jobs, :index_good_job_jobs_for_candidate_lookup)
83
+
84
+ migration_pending_warning!
85
+ false
86
+ end
59
87
  end
60
88
 
61
89
  # The ActiveJob job class, as a string
@@ -71,14 +99,14 @@ module GoodJob
71
99
  # Build an ActiveJob instance and deserialize the arguments, using `#active_job_data`.
72
100
  #
73
101
  # @param ignore_deserialization_errors [Boolean]
74
- # Whether to ignore ActiveJob::DeserializationError when deserializing the arguments.
102
+ # Whether to ignore ActiveJob::DeserializationError and NameError when deserializing the arguments.
75
103
  # This is most useful if you aren't planning to use the arguments directly.
76
104
  def active_job(ignore_deserialization_errors: false)
77
105
  ActiveJob::Base.deserialize(active_job_data).tap do |aj|
78
106
  aj.send(:deserialize_arguments_if_needed)
79
- rescue ActiveJob::DeserializationError
80
- raise unless ignore_deserialization_errors
81
107
  end
108
+ rescue ActiveJob::DeserializationError, NameError
109
+ raise unless ignore_deserialization_errors
82
110
  end
83
111
 
84
112
  private
@@ -88,6 +116,7 @@ module GoodJob
88
116
  .tap do |job_data|
89
117
  job_data["provider_job_id"] = id
90
118
  job_data["good_job_concurrency_key"] = concurrency_key if concurrency_key
119
+ job_data["good_job_labels"] = Array(labels) if self.class.labels_migrated? && labels.present?
91
120
  end
92
121
  end
93
122
  end
@@ -101,7 +101,7 @@ module GoodJob
101
101
 
102
102
  active_jobs = add(active_jobs, &block)
103
103
 
104
- Rails.application.reloader.wrap do
104
+ Rails.application.executor.wrap do
105
105
  record.with_advisory_lock(function: "pg_advisory_lock") do
106
106
  record.update!(enqueued_at: Time.current)
107
107
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GoodJob
4
- # ActiveRecord model that represents an +ActiveJob+ job.
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 Jobs were completed before the given timestamp. If no timestamp is
154
- # provided, get all jobs that have been completed. By default, GoodJob
155
- # destroys jobs after they are completed and this will find no jobs.
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