good_job 4.21.1 → 4.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -2
  3. data/README.md +68 -21
  4. data/app/controllers/good_job/batches_controller.rb +3 -1
  5. data/app/controllers/good_job/jobs_controller.rb +1 -0
  6. data/app/filters/good_job/jobs_filter.rb +8 -0
  7. data/app/frontend/good_job/icons.svg +12 -0
  8. data/app/frontend/good_job/style.css +6 -0
  9. data/app/frontend/good_job/vendor/bootstrap/bootstrap.bundle.min.js +3 -3
  10. data/app/frontend/good_job/vendor/bootstrap/bootstrap.min.css +3 -3
  11. data/app/frontend/good_job/vendor/chartjs/chart.min.js +10 -15
  12. data/app/frontend/good_job/vendor/es_module_shims.js +1486 -1
  13. data/app/frontend/good_job/vendor/stimulus.js +2314 -2159
  14. data/app/frontend/good_job/vendor/turbo.js +6 -6
  15. data/app/helpers/good_job/application_helper.rb +42 -0
  16. data/app/models/good_job/concurrency_claim.rb +18 -0
  17. data/app/models/good_job/job.rb +1 -0
  18. data/app/views/good_job/batches/_jobs.erb +1 -2
  19. data/app/views/good_job/jobs/_table.erb +1 -2
  20. data/app/views/good_job/jobs/show.html.erb +24 -0
  21. data/app/views/layouts/good_job/application.html.erb +2 -0
  22. data/config/locales/az.yml +6 -0
  23. data/config/locales/de.yml +6 -0
  24. data/config/locales/en.yml +6 -0
  25. data/config/locales/es.yml +6 -0
  26. data/config/locales/fr.yml +6 -0
  27. data/config/locales/it.yml +6 -0
  28. data/config/locales/ja.yml +6 -0
  29. data/config/locales/ko.yml +6 -0
  30. data/config/locales/nl.yml +6 -0
  31. data/config/locales/pt-BR.yml +6 -0
  32. data/config/locales/ru.yml +6 -0
  33. data/config/locales/tr.yml +6 -0
  34. data/config/locales/uk.yml +6 -0
  35. data/config/locales/zh-CN.yml +6 -0
  36. data/lib/good_job/active_job_extensions/concurrency.rb +28 -2
  37. data/lib/good_job/active_job_extensions/labels.rb +27 -10
  38. data/lib/good_job/cli.rb +5 -1
  39. data/lib/good_job/configuration.rb +49 -7
  40. data/lib/good_job/multi_scheduler.rb +1 -1
  41. data/lib/good_job/scheduler.rb +2 -2
  42. data/lib/good_job/version.rb +1 -1
  43. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 510354d3834b40133fff5b01cda0ac035f58b327317098467a305ac2ca5372d4
4
- data.tar.gz: 0bee2064ac6fc2f6d89c69e22ed3639d07341120a4dfecb0d77e025e94455148
3
+ metadata.gz: c3707d55ab1de17d450f3b52e30739b25350ed229e7fad992ab9f56aa01c88fc
4
+ data.tar.gz: 1af86ced85ba5487a1b3c13eac8e4f2988c6685153fee444fd34afa62533ef7b
5
5
  SHA512:
6
- metadata.gz: ae50900ba6a6db18dc13112a3999a12fc215e1f0f856e761b253fbfa02689ded6a01e3c2bb7aaf776465e822fb7b0ca1d2075dff9c784fc14e62a4ebbec82dcb
7
- data.tar.gz: 5b939f61fa88f4dbdfed4ef48bc7ea0d0702e09b01c8e7ca7008e2e9cf4c112568e0a299197eb7985da9fb05e89a81d5d332a4bedbc98aac7dad6268d9f91579
6
+ metadata.gz: 56311442c755f60a717bc23c42f193f3bfc15f31254527320e9183cc681cc43c9a87d89fd5e9c2efe305d14f87f6c3cafa0d9a2e5443c5cad3eafa7da31f5674
7
+ data.tar.gz: '0875bd2051120c9cd80d11e781713b2c13a6a05d2fdfa38f54dfdb0c3a616b3cbe4d23769db811211feaf7feb49cb1d2a1bf4e72baa31a9127f10b82ce18f5fd'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [v4.22.0](https://github.com/bensheldon/good_job/tree/v4.22.0) (2026-10-09)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v4.21.1...v4.22.0)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Rename max\_threads config to threads and deprecate max\_threads [\#1846](https://github.com/bensheldon/good_job/pull/1846) ([bensheldon](https://github.com/bensheldon))
10
+
11
+ **Closed issues:**
12
+
13
+ - CI: json 3.0.2 removed `quirks_mode`, breaking ActiveSupport's JSON encoder on every test job [\#1816](https://github.com/bensheldon/good_job/issues/1816)
14
+
15
+ **Merged pull requests:**
16
+
17
+ - Restore JRuby gems to Gemfile.lock and add a spec guarding it [\#1861](https://github.com/bensheldon/good_job/pull/1861) ([bensheldon](https://github.com/bensheldon))
18
+ - Upgrade vendored frontend libraries \(Turbo, Stimulus, es-module-shims, Bootstrap, Chart.js\) [\#1860](https://github.com/bensheldon/good_job/pull/1860) ([bensheldon](https://github.com/bensheldon))
19
+ - Upgrade dev environment: Ruby 4.0.7, Bundler 4.0.22, and gems [\#1859](https://github.com/bensheldon/good_job/pull/1859) ([bensheldon](https://github.com/bensheldon))
20
+ - Don't crash demo when git is unavailable \(e.g. Heroku\) [\#1858](https://github.com/bensheldon/good_job/pull/1858) ([bensheldon](https://github.com/bensheldon))
21
+ - Add apply\_label: option to good\_job\_concurrency\_rule [\#1857](https://github.com/bensheldon/good_job/pull/1857) ([bensheldon](https://github.com/bensheldon))
22
+ - Deprecate good\_job\_control\_concurrency\_with and key-only concurrency rules in favor of labels [\#1856](https://github.com/bensheldon/good_job/pull/1856) ([bensheldon](https://github.com/bensheldon))
23
+ - Show concurrency claims on the dashboard [\#1855](https://github.com/bensheldon/good_job/pull/1855) ([bensheldon](https://github.com/bensheldon))
24
+ - Allow json 3 for Rails versions that support it; pin json \< 3 only for older Rails [\#1854](https://github.com/bensheldon/good_job/pull/1854) ([bensheldon](https://github.com/bensheldon))
25
+
3
26
  ## [v4.21.1](https://github.com/bensheldon/good_job/tree/v4.21.1) (2026-10-07)
4
27
 
5
28
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v4.21.0...v4.21.1)
@@ -3741,7 +3764,7 @@
3741
3764
 
3742
3765
  **Fixed bugs:**
3743
3766
 
3744
- - Don’t attempt to enforce concurrency limits with other queue adapters [\#333](https://github.com/bensheldon/good_job/pull/333) ([codyrobbins](https://github.com/codyrobbins))
3767
+ - Don’t attempt to enforce concurrency limits with other queue adapters [\#333](https://github.com/bensheldon/good_job/pull/333) ([CodyRobbins](https://github.com/CodyRobbins))
3745
3768
 
3746
3769
  ## [v1.13.0](https://github.com/bensheldon/good_job/tree/v1.13.0) (2021-08-18)
3747
3770
 
@@ -3768,7 +3791,7 @@
3768
3791
 
3769
3792
  **Fixed bugs:**
3770
3793
 
3771
- - Fixes for race conditions in ActiveJob concurrency extension [\#326](https://github.com/bensheldon/good_job/pull/326) ([codyrobbins](https://github.com/codyrobbins))
3794
+ - Fixes for race conditions in ActiveJob concurrency extension [\#326](https://github.com/bensheldon/good_job/pull/326) ([CodyRobbins](https://github.com/CodyRobbins))
3772
3795
 
3773
3796
  **Merged pull requests:**
3774
3797
 
data/README.md CHANGED
@@ -49,6 +49,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
49
49
  - [Concurrency controls](#concurrency-controls)
50
50
  - [Dynamic labels](#dynamic-labels)
51
51
  - [How concurrency controls work](#how-concurrency-controls-work)
52
+ - [Migrating from concurrency keys to labels](#migrating-from-concurrency-keys-to-labels)
52
53
  - [Cron-style repeating/recurring jobs](#cron-style-repeatingrecurring-jobs)
53
54
  - [Bulk enqueue](#bulk-enqueue)
54
55
  - [Batches](#batches)
@@ -198,7 +199,8 @@ Usage:
198
199
 
199
200
  Options:
200
201
  [--queues=QUEUE_LIST] # Queues or pools to work from. (env var: GOOD_JOB_QUEUES, default: *)
201
- [--max-threads=COUNT] # Default number of threads per pool to use for working jobs. (env var: GOOD_JOB_MAX_THREADS, default: 5)
202
+ [--threads=COUNT] # Default number of threads per pool to use for working jobs. (env var: GOOD_JOB_THREADS, default: 5)
203
+ [--max-threads=COUNT] # (DEPRECATED: use --threads) (env var: GOOD_JOB_MAX_THREADS, default: 5)
202
204
  [--poll-interval=SECONDS] # Interval between polls for available jobs in seconds (env var: GOOD_JOB_POLL_INTERVAL, default: 10)
203
205
  [--max-cache=COUNT] # Maximum number of scheduled jobs to cache in memory (env var: GOOD_JOB_MAX_CACHE, default: 10000)
204
206
  [--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))
@@ -262,7 +264,7 @@ Rails.application.configure do
262
264
  config.good_job.on_thread_error = -> (exception) { Rails.error.report(exception) }
263
265
  config.good_job.execution_mode = :async
264
266
  config.good_job.queues = '*'
265
- config.good_job.max_threads = 5
267
+ config.good_job.threads = 5
266
268
  config.good_job.poll_interval = 30 # seconds
267
269
  config.good_job.shutdown_timeout = 25 # seconds
268
270
  config.good_job.enable_cron = true
@@ -277,7 +279,7 @@ Rails.application.configure do
277
279
  on_thread_error: -> (exception) { Rails.error.report(exception) },
278
280
  execution_mode: :async,
279
281
  queues: '*',
280
- max_threads: 5,
282
+ threads: 5,
281
283
  poll_interval: 30,
282
284
  shutdown_timeout: 25,
283
285
  enable_cron: true,
@@ -300,7 +302,7 @@ Available configuration options are:
300
302
  - `:async` (or `:async_server`) executes jobs in separate threads within the Rails web server process (`bundle exec rails server`). It can be more economical for small workloads because you don’t need a separate machine or environment for running your jobs, but if your web server is under heavy load or your jobs require a lot of resources, you should choose `:external` instead. When not in the Rails web server, jobs will execute in `:external` mode to ensure jobs are not executed within `rails console`, `rails db:migrate`, `rails assets:prepare`, etc.
301
303
  - `:async_all` executes jobs in separate threads in _any_ Rails process.
302
304
  - `queues` (string) sets queues or pools to execute jobs. You can also set this with the environment variable `GOOD_JOB_QUEUES`.
303
- - `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`.
305
+ - `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_THREADS`. (Formerly `max_threads` / `GOOD_JOB_MAX_THREADS`, which are deprecated but still honored.)
304
306
  - `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.
305
307
  - production default: 10 seconds (in case of a LISTEN/NOTIFY blip)
306
308
  - 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`.
@@ -567,6 +569,11 @@ class MyJob < ApplicationJob
567
569
  # `good_job_labels`.
568
570
  label: "email",
569
571
 
572
+ # Apply the rule's label to every job of this class (and its subclasses),
573
+ # so the jobs don't need to be enqueued with it. Defaults to false.
574
+ # A Lambda/Proc label that returns nil is not applied.
575
+ apply_label: true,
576
+
570
577
  # Maximum number of unfinished jobs with this label to allow.
571
578
  # Can be an Integer or Lambda/Proc invoked in the context of the job.
572
579
  total_limit: 1,
@@ -609,13 +616,31 @@ Jobs must be enqueued with the matching label for rules to take effect:
609
616
  MyJob.set(good_job_labels: ["email"]).perform_later
610
617
  ```
611
618
 
612
- Supplying both `label:` and `key:` to `good_job_concurrency_rule` is deprecated. For labelled rules, `key:` is ignored: jobs sharing the label use the same advisory lock for concurrency checks. Remove `key:` from these rules. The legacy `good_job_control_concurrency_with(key: ...)` interface remains supported.
619
+ Supplying both `label:` and `key:` to `good_job_concurrency_rule` is deprecated. For labelled rules, `key:` is ignored: jobs sharing the label use the same advisory lock for concurrency checks. Remove `key:` from these rules. Rules with `key:` and no `label:` are also deprecated; see [Migrating from concurrency keys to labels](#migrating-from-concurrency-keys-to-labels).
613
620
 
614
621
  #### Dynamic labels
615
622
 
616
623
  A rule's `label:` can also be a Lambda/Proc that is invoked in the context of the job instance, for example to derive the label from job arguments. The lambda resolves the label to check against; the job's `good_job_labels` must still contain it for the rule to apply. Rule labels and job labels are converted to strings and stripped of surrounding whitespace when matched, consistent with how labels are stored.
617
624
 
618
- To apply a dynamic label to every job of a class, set a Lambda/Proc in the class-level `good_job_labels`. It is invoked in the context of the job when the job is initialized, so the label is present for checks at both enqueue and perform time:
625
+ To apply a rule's label to every job of a class, use `apply_label: true`. The label is resolved in the context of the job when the job is initialized, so it is present for checks at both enqueue and perform time, including for jobs enqueued in bulk. Labels passed with `MyJob.set(good_job_labels: [...])` are added to it rather than replacing it:
626
+
627
+ ```ruby
628
+ class MyJob < ApplicationJob
629
+ include GoodJob::ActiveJobExtensions::Concurrency
630
+
631
+ good_job_concurrency_rule(
632
+ label: -> { "user-#{arguments.first[:user_id]}" },
633
+ apply_label: true,
634
+ total_limit: 1
635
+ )
636
+
637
+ def perform(user_id:)
638
+ # do work
639
+ end
640
+ end
641
+ ```
642
+
643
+ Class-level `good_job_labels` can also be Lambdas/Procs, invoked in the context of the job when it is initialized:
619
644
 
620
645
  ```ruby
621
646
  class MyJob < ApplicationJob
@@ -641,7 +666,7 @@ class MyJob < ApplicationJob
641
666
  include GoodJob::ActiveJobExtensions::Concurrency
642
667
 
643
668
  before_enqueue do |job|
644
- job.good_job_labels = [job.arguments.first[:user_id].to_s]
669
+ job.good_job_labels |= [job.arguments.first[:user_id].to_s]
645
670
  end
646
671
 
647
672
  good_job_concurrency_rule(
@@ -673,9 +698,31 @@ GoodJob's concurrency control strategy for `perform_limit` is "optimistic retry
673
698
  - First-in-first-out job execution order is not strictly preserved: a waiting job that is re-scheduled can be overtaken by a newly enqueued job, and jobs retried with incremental back-off run in backoff order.
674
699
  - For pessimistic usecases that collisions are expected, use number of threads/processes (e.g., `good_job --queues "serial:1;-serial:5"`) to control concurrency. It is also a good idea to use `perform_limit` as backstop.
675
700
 
676
- #### Legacy: `good_job_control_concurrency_with`
701
+ #### Migrating from concurrency keys to labels
702
+
703
+ `good_job_control_concurrency_with`, and `good_job_concurrency_rule` with `key:` and no `label:`, are deprecated and will raise in GoodJob v5, which will also remove the `good_jobs.concurrency_key` column. They scope limits to a concurrency _key_ stored in that column. Replace them with a labelled rule and apply the same value to the job as a label:
704
+
705
+ ```ruby
706
+ class MyJob < ApplicationJob
707
+ include GoodJob::ActiveJobExtensions::Concurrency
708
+
709
+ # Before
710
+ good_job_control_concurrency_with(total_limit: 1, key: -> { "MyJob-#{arguments.first}" })
711
+
712
+ # After
713
+ self.good_job_labels = [-> { "MyJob-#{arguments.first}" }]
714
+ good_job_concurrency_rule(total_limit: 1, label: -> { "MyJob-#{arguments.first}" })
715
+ end
716
+ ```
717
+
718
+ - A static key becomes a static label: `self.good_job_labels = ["my-key"]` and `good_job_concurrency_rule(label: "my-key", ...)`.
719
+ - Labels can also be applied in a `before_enqueue` callback; see [Dynamic labels](#dynamic-labels).
720
+ - If you did not supply a `key:`, the job class name was used; use it as the label.
721
+ - If you supplied `key: nil` to disable concurrency control in a subclass: rules are inherited, but a labelled rule only applies to jobs carrying its label, so don't apply the label in that subclass (e.g. with a Lambda label that returns `nil`).
722
+ - `total_limit:`, `enqueue_limit:`, `perform_limit:`, `enqueue_throttle:` and `perform_throttle:` are unchanged.
723
+ - Jobs enqueued before the change do not have the label and are not counted by the new rule, so limits may be exceeded until those jobs finish.
677
724
 
678
- The original concurrency interface uses a single configuration hash and scopes limits to a concurrency _key_ (a string derived from the job) stored on the job record, rather than a label. It remains fully supported.
725
+ The deprecated interface is documented below for reference:
679
726
 
680
727
  ```ruby
681
728
  class MyJob < ApplicationJob
@@ -1257,7 +1304,7 @@ By default, GoodJob creates a single thread execution pool that will execute job
1257
1304
 
1258
1305
  ```bash
1259
1306
  $ GOOD_JOB_QUEUES="transactional_messages:2;batch_processing:1;-transactional_messages,batch_processing:2;*" \
1260
- GOOD_JOB_MAX_THREADS=5 \
1307
+ GOOD_JOB_THREADS=5 \
1261
1308
  bundle exec good_job
1262
1309
  ```
1263
1310
 
@@ -1271,9 +1318,9 @@ By default, GoodJob creates a single thread execution pool that will execute job
1271
1318
  # Procfile
1272
1319
 
1273
1320
  # Separate process types
1274
- worker: bundle exec good_job --max-threads=5
1275
- transactional_worker: bundle exec good_job --queues="transactional_messages" --max-threads=2
1276
- batch_worker: bundle exec good_job --queues="batch_processing" --max-threads=1
1321
+ worker: bundle exec good_job --threads=5
1322
+ transactional_worker: bundle exec good_job --queues="transactional_messages" --threads=2
1323
+ batch_worker: bundle exec good_job --queues="batch_processing" --threads=1
1277
1324
  ```
1278
1325
 
1279
1326
  To optimize for CPU performance at the expense of greater memory and system resource usage, while keeping a single process type (and thus a single dyno), combine several processes and wait for them:
@@ -1282,7 +1329,7 @@ By default, GoodJob creates a single thread execution pool that will execute job
1282
1329
  # Procfile
1283
1330
 
1284
1331
  # Combined multi-process
1285
- combined_worker: bundle exec good_job --max-threads=5 & bundle exec good_job --queues="transactional_messages" --max-threads=2 & bundle exec good_job --queues="batch_processing" --max-threads=1 & wait -n
1332
+ combined_worker: bundle exec good_job --threads=5 & bundle exec good_job --queues="transactional_messages" --threads=2 & bundle exec good_job --queues="batch_processing" --threads=1 & wait -n
1286
1333
  ```
1287
1334
 
1288
1335
  Keep in mind, queue operations and management is an advanced discipline. This stuff is complex, especially for heavy workloads and unique processing requirements. Good job 👍
@@ -1291,7 +1338,7 @@ Keep in mind, queue operations and management is an advanced discipline. This st
1291
1338
 
1292
1339
  GoodJob job executor processes require the following database connections:
1293
1340
 
1294
- - 1 connection per execution pool thread. E.g., `--queues=mice:2;elephants:1` is 3 threads and thus 3 connections. Pool size defaults to `--max-threads`.
1341
+ - 1 connection per execution pool thread. E.g., `--queues=mice:2;elephants:1` is 3 threads and thus 3 connections. Pool size defaults to `--threads`.
1295
1342
  - 2 additional connections that GoodJob uses for utility functionality (e.g. LISTEN/NOTIFY, cron, etc.)
1296
1343
  - 1 connection per subthread, if your application makes multithreaded database queries (e.g. `load_async`) within a job.
1297
1344
 
@@ -1310,12 +1357,12 @@ When GoodJob runs in `:async` mode (in Rails's development environment, by defau
1310
1357
  - `ENV.fetch("RAILS_MAX_THREADS", 5)` is the number of threads used by the web server
1311
1358
  - `1` is the number of connections used by the job listener
1312
1359
  - `2` is the number of connections used by the cron scheduler and executor
1313
- - `ENV.fetch("GOOD_JOB_MAX_THREADS", 5)` is the number of threads used to perform jobs
1360
+ - `ENV.fetch("GOOD_JOB_THREADS", 5)` is the number of threads used to perform jobs
1314
1361
 
1315
1362
  ```yaml
1316
1363
  # config/database.yml
1317
1364
 
1318
- pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5).to_i + 1 + 2 + ENV.fetch("GOOD_JOB_MAX_THREADS", 5).to_i %>
1365
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5).to_i + 1 + 2 + ENV.fetch("GOOD_JOB_THREADS", 5).to_i %>
1319
1366
  ```
1320
1367
 
1321
1368
  When GoodJob runs in `:external` mode (in Rails' production environment, by default), the following database pool configurations work for web servers and worker processes, respectively.
@@ -1329,7 +1376,7 @@ pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5) %>
1329
1376
  ```yaml
1330
1377
  # config/database.yml
1331
1378
 
1332
- pool: <%= 1 + 2 + ENV.fetch("GOOD_JOB_MAX_THREADS", 5).to_i %>
1379
+ pool: <%= 1 + 2 + ENV.fetch("GOOD_JOB_THREADS", 5).to_i %>
1333
1380
  ```
1334
1381
 
1335
1382
  ### Production setup
@@ -1417,7 +1464,7 @@ GoodJob can execute jobs "async" in the same process as the web server (e.g. `bi
1417
1464
  # Or with more configuration
1418
1465
  config.good_job = {
1419
1466
  execution_mode: :async,
1420
- max_threads: 4,
1467
+ threads: 4,
1421
1468
  poll_interval: 30
1422
1469
  }
1423
1470
  ```
@@ -1425,7 +1472,7 @@ GoodJob can execute jobs "async" in the same process as the web server (e.g. `bi
1425
1472
  - Or, with environment variables:
1426
1473
 
1427
1474
  ```bash
1428
- GOOD_JOB_EXECUTION_MODE=async GOOD_JOB_MAX_THREADS=4 GOOD_JOB_POLL_INTERVAL=30 bin/rails server
1475
+ GOOD_JOB_EXECUTION_MODE=async GOOD_JOB_THREADS=4 GOOD_JOB_POLL_INTERVAL=30 bin/rails server
1429
1476
  ```
1430
1477
 
1431
1478
  Depending on your application configuration, you may need to take additional steps:
@@ -1434,7 +1481,7 @@ Depending on your application configuration, you may need to take additional ste
1434
1481
 
1435
1482
  ```yaml
1436
1483
  # config/database.yml
1437
- pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5).to_i + ENV.fetch("GOOD_JOB_MAX_THREADS", 4).to_i %>
1484
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5).to_i + ENV.fetch("GOOD_JOB_THREADS", 4).to_i %>
1438
1485
  ```
1439
1486
 
1440
1487
  - When running Puma with workers (`WEB_CONCURRENCY > 0`) or another process-forking web server, GoodJob's threadpool schedulers should be stopped before forking, restarted after fork, and cleanly shut down on exit. Stopping GoodJob's scheduler pre-fork is recommended to ensure that GoodJob does not continue executing jobs in the parent/controller process. For example, with Puma:
@@ -7,7 +7,9 @@ module GoodJob
7
7
  end
8
8
 
9
9
  def show
10
- @batch = GoodJob::BatchRecord.find(params[:id])
10
+ batches = GoodJob::BatchRecord.all
11
+ batches = batches.preload(jobs: :concurrency_claims, callback_jobs: :concurrency_claims) if GoodJob::ConcurrencyClaim.table_exists?
12
+ @batch = batches.find(params[:id])
11
13
  end
12
14
 
13
15
  def retry
@@ -62,6 +62,7 @@ module GoodJob
62
62
 
63
63
  def show
64
64
  @job = Job.includes(:executions).includes_advisory_locks.find(params[:id])
65
+ @concurrency_claims = ConcurrencyClaim.table_exists? ? @job.concurrency_claims.to_a.sort_by(&:created_at) : []
65
66
  end
66
67
 
67
68
  def discard
@@ -4,6 +4,14 @@ module GoodJob
4
4
  class JobsFilter < BaseFilter
5
5
  UUID_REGEX = /\A[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}\z/i
6
6
 
7
+ def records
8
+ @_records ||= begin
9
+ records = super
10
+ records = records.preload(:concurrency_claims) if GoodJob::ConcurrencyClaim.table_exists?
11
+ records
12
+ end
13
+ end
14
+
7
15
  def state_names
8
16
  %w[scheduled retried queued running succeeded discarded]
9
17
  end
@@ -5,6 +5,10 @@
5
5
  <path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" />
6
6
  <path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z" />
7
7
  </symbol>
8
+ <!-- https://icons.getbootstrap.com/icons/arrow-up-circle-fill/ -->
9
+ <symbol id="arrow_up_circle_fill" viewBox="0 0 16 16">
10
+ <path d="M16 8A8 8 0 1 0 0 8a8 8 0 0 0 16 0m-7.5 3.5a.5.5 0 0 1-1 0V5.707L5.354 7.854a.5.5 0 1 1-.708-.708l3-3a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707z" />
11
+ </symbol>
8
12
  <!-- https://icons.getbootstrap.com/icons/check-circle/ -->
9
13
  <symbol id="check" viewBox="0 0 16 16">
10
14
  <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
@@ -41,11 +45,19 @@
41
45
  <symbol id="globe" viewBox="0 0 16 16">
42
46
  <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m7.5-6.923c-.67.204-1.335.82-1.887 1.855A8 8 0 0 0 5.145 4H7.5zM4.09 4a9.3 9.3 0 0 1 .64-1.539 7 7 0 0 1 .597-.933A7.03 7.03 0 0 0 2.255 4zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a7 7 0 0 0-.656 2.5zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5zM8.5 5v2.5h2.99a12.5 12.5 0 0 0-.337-2.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5zM5.145 12q.208.58.468 1.068c.552 1.035 1.218 1.65 1.887 1.855V12zm.182 2.472a7 7 0 0 1-.597-.933A9.3 9.3 0 0 1 4.09 12H2.255a7 7 0 0 0 3.072 2.472M3.82 11a13.7 13.7 0 0 1-.312-2.5h-2.49c.062.89.291 1.733.656 2.5zm6.853 3.472A7 7 0 0 0 13.745 12H11.91a9.3 9.3 0 0 1-.64 1.539 7 7 0 0 1-.597.933M8.5 12v2.923c.67-.204 1.335-.82 1.887-1.855q.26-.487.468-1.068zm3.68-1h2.146c.365-.767.594-1.61.656-2.5h-2.49a13.7 13.7 0 0 1-.312 2.5m2.802-3.5a7 7 0 0 0-.656-2.5H12.18c.174.782.282 1.623.312 2.5zM11.27 2.461c.247.464.462.98.64 1.539h1.835a7 7 0 0 0-3.072-2.472c.218.284.418.598.597.933M10.855 4a8 8 0 0 0-.468-1.068C9.835 1.897 9.17 1.282 8.5 1.077V4z" />
43
47
  </symbol>
48
+ <!-- https://icons.getbootstrap.com/icons/hourglass-split/ -->
49
+ <symbol id="hourglass_split" viewBox="0 0 16 16">
50
+ <path d="M2.5 15a.5.5 0 1 1 0-1h1v-1a4.5 4.5 0 0 1 2.557-4.06c.29-.139.443-.377.443-.59v-.7c0-.213-.154-.451-.443-.59A4.5 4.5 0 0 1 3.5 3V2h-1a.5.5 0 0 1 0-1h11a.5.5 0 0 1 0 1h-1v1a4.5 4.5 0 0 1-2.557 4.06c-.29.139-.443.377-.443.59v.7c0 .213.154.451.443.59A4.5 4.5 0 0 1 12.5 13v1h1a.5.5 0 0 1 0 1zm2-13v1c0 .537.12 1.045.337 1.5h6.326c.216-.455.337-.963.337-1.5V2zm3 6.35c0 .701-.478 1.236-1.011 1.492A3.5 3.5 0 0 0 4.5 13s.866-1.299 3-1.48zm1 0v3.17c2.134.181 3 1.48 3 1.48a3.5 3.5 0 0 0-1.989-3.158C8.978 9.586 8.5 9.052 8.5 8.351z" />
51
+ </symbol>
44
52
  <!-- https://icons.getbootstrap.com/icons/info-circle/ -->
45
53
  <symbol id="info" viewBox="0 0 16 16">
46
54
  <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
47
55
  <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z" />
48
56
  </symbol>
57
+ <!-- https://icons.getbootstrap.com/icons/lock-fill/ -->
58
+ <symbol id="lock_fill" viewBox="0 0 16 16">
59
+ <path d="M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2m3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2" />
60
+ </symbol>
49
61
  <!-- https://icons.getbootstrap.com/icons/moon-stars-fill/ -->
50
62
  <symbol id="moon_stars_fill" viewBox="0 0 16 16">
51
63
  <path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z" />
@@ -146,6 +146,12 @@
146
146
  width: 1rem;
147
147
  }
148
148
 
149
+ .svg-icon.badge-icon {
150
+ height: 1em;
151
+ width: 1em;
152
+ vertical-align: top;
153
+ }
154
+
149
155
  .badge-group {
150
156
  position: relative;
151
157
  display: inline-flex;