good_job 3.16.3 → 3.17.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/README.md +41 -15
  4. data/app/frontend/good_job/application.js +2 -0
  5. data/app/frontend/good_job/modules/theme_controller.js +44 -0
  6. data/app/frontend/good_job/vendor/bootstrap/bootstrap.bundle.min.js +3 -3
  7. data/app/frontend/good_job/vendor/bootstrap/bootstrap.min.css +3 -4
  8. data/app/models/concerns/good_job/{lockable.rb → advisory_lockable.rb} +1 -1
  9. data/app/models/good_job/base_execution.rb +24 -1
  10. data/app/models/good_job/batch.rb +2 -2
  11. data/app/models/good_job/batch_record.rb +1 -1
  12. data/app/models/good_job/execution.rb +0 -21
  13. data/app/models/good_job/process.rb +5 -1
  14. data/app/views/good_job/batches/_jobs.erb +3 -3
  15. data/app/views/good_job/batches/_table.erb +1 -1
  16. data/app/views/good_job/batches/show.html.erb +1 -1
  17. data/app/views/good_job/cron_entries/index.html.erb +2 -2
  18. data/app/views/good_job/jobs/_executions.erb +2 -2
  19. data/app/views/good_job/jobs/_table.erb +10 -9
  20. data/app/views/good_job/jobs/show.html.erb +2 -2
  21. data/app/views/good_job/processes/index.html.erb +3 -3
  22. data/app/views/good_job/shared/_footer.erb +1 -1
  23. data/app/views/good_job/shared/_navbar.erb +50 -7
  24. data/app/views/good_job/shared/icons/_circle_half.html.erb +4 -0
  25. data/app/views/good_job/shared/icons/_moon_stars_fill.html.erb +5 -0
  26. data/app/views/good_job/shared/icons/_sun_fill.html.erb +4 -0
  27. data/app/views/layouts/good_job/application.html.erb +9 -1
  28. data/config/locales/de.yml +5 -0
  29. data/config/locales/en.yml +5 -0
  30. data/config/locales/es.yml +5 -0
  31. data/config/locales/fr.yml +5 -0
  32. data/config/locales/ja.yml +5 -0
  33. data/config/locales/nl.yml +5 -0
  34. data/config/locales/ru.yml +5 -0
  35. data/config/locales/tr.yml +5 -0
  36. data/config/locales/uk.yml +5 -0
  37. data/lib/good_job/capsule.rb +5 -4
  38. data/lib/good_job/cli.rb +6 -2
  39. data/lib/good_job/configuration.rb +2 -5
  40. data/lib/good_job/cron_manager.rb +3 -2
  41. data/lib/good_job/http_server.rb +75 -0
  42. data/lib/good_job/log_subscriber.rb +18 -0
  43. data/lib/good_job/notifier.rb +59 -44
  44. data/lib/good_job/probe_server.rb +4 -8
  45. data/lib/good_job/sd_notify.rb +157 -0
  46. data/lib/good_job/shared_executor.rb +69 -0
  47. data/lib/good_job/systemd_service.rb +69 -0
  48. data/lib/good_job/version.rb +1 -1
  49. data/lib/good_job.rb +6 -0
  50. metadata +11 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3929d3de9d0c69de6aa34b238573dd19eabb0b6753b28a06b186cfc6972b621b
4
- data.tar.gz: d927b1cc39f993f64a4b07594cb7215975e02d55cb212b420122b2c672d5f2d4
3
+ metadata.gz: 946d6d7912809cf31d3f79c0dc7e2c074b20c7bcd853d6c3a9ab35faa5f4f6aa
4
+ data.tar.gz: d33a7a41a7c8c259d71c5e8caa7fb268ec0db2c7516a4fb45d937c4e05d5fb64
5
5
  SHA512:
6
- metadata.gz: 34ac854233932322ad76eaea4d41879b9d97c08a204b6f689affedbe861b86bc5c83b6c02dd1132c267f7f9129d4e0ace042e9299f4fe522fdf9d590b6c0cf33
7
- data.tar.gz: a8007ea55894eb72494935dff5269d1e54d157eab334b823769884cc3d83d1a37be3d9cb44e603ba5a132cb3993ba8dd8e306c4d3974f9a2bf4dc2603add5706
6
+ metadata.gz: e849433834f758352c918379f1c727d3b992cd6843f9f27de4768d2f7845402f5c9b418cb93da285811df55882d0a0a6acac90bcedf1bdeac9dbafca66e7af54
7
+ data.tar.gz: fe3ae7523b7d9307a085a298a771301b3d9707495a24866eec113bbc172a83ffedfe68e452c1b925e0e04f2a5a54175a995c2c312f1f3033e860615182015c2a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,53 @@
1
1
  # Changelog
2
2
 
3
+ ## [v3.17.0](https://github.com/bensheldon/good_job/tree/v3.17.0) (2023-08-06)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.16.4...v3.17.0)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Add Dark Mode color theme for Dashboard [\#1031](https://github.com/bensheldon/good_job/pull/1031) ([bensheldon](https://github.com/bensheldon))
10
+ - Automatically send status notifications to systemd [\#1029](https://github.com/bensheldon/good_job/pull/1029) ([Mr0grog](https://github.com/Mr0grog))
11
+
12
+ **Closed issues:**
13
+
14
+ - Add systemd/sd\_notify support to CLI [\#1027](https://github.com/bensheldon/good_job/issues/1027)
15
+ - Cron job by default runs on the web server even when "async" execution mode is not specified [\#1026](https://github.com/bensheldon/good_job/issues/1026)
16
+ - Replace webrick with a small/simple custom rack-compatible http server [\#1017](https://github.com/bensheldon/good_job/issues/1017)
17
+ - Dark mode for the dashboard ? [\#974](https://github.com/bensheldon/good_job/issues/974)
18
+
19
+ **Merged pull requests:**
20
+
21
+ - Replace Webrick with custom simple http server [\#1030](https://github.com/bensheldon/good_job/pull/1030) ([dixpac](https://github.com/dixpac))
22
+ - Bump appraisal from `b200e63` to `feb78bc` [\#1025](https://github.com/bensheldon/good_job/pull/1025) ([dependabot[bot]](https://github.com/apps/dependabot))
23
+ - Bump net-imap from 0.3.6 to 0.3.7 [\#1024](https://github.com/bensheldon/good_job/pull/1024) ([dependabot[bot]](https://github.com/apps/dependabot))
24
+ - Bump rack from 2.2.7 to 2.2.8 [\#1023](https://github.com/bensheldon/good_job/pull/1023) ([dependabot[bot]](https://github.com/apps/dependabot))
25
+
26
+ ## [v3.16.4](https://github.com/bensheldon/good_job/tree/v3.16.4) (2023-07-30)
27
+
28
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.16.3...v3.16.4)
29
+
30
+ **Implemented enhancements:**
31
+
32
+ - Add database\_connection\_pool stats to `GoodJob::Process.current_state` [\#1019](https://github.com/bensheldon/good_job/pull/1019) ([dixpac](https://github.com/dixpac))
33
+
34
+ **Fixed bugs:**
35
+
36
+ - Move `Execution#active_job` to BaseExecution to share with Job; refactor `Batch#active_jobs` to use job directly [\#1022](https://github.com/bensheldon/good_job/pull/1022) ([bensheldon](https://github.com/bensheldon))
37
+
38
+ **Closed issues:**
39
+
40
+ - Notifier errored: ArgumentError: wrong number of arguments \(given 1, expected 0\) [\#1016](https://github.com/bensheldon/good_job/issues/1016)
41
+ - Understanding Database Connections and Cron [\#1013](https://github.com/bensheldon/good_job/issues/1013)
42
+ - Experiencing various database exceptions with Rails 7.1 [\#796](https://github.com/bensheldon/good_job/issues/796)
43
+
44
+ **Merged pull requests:**
45
+
46
+ - Refactor Notifier to ensure \#restart is threadsafe [\#1021](https://github.com/bensheldon/good_job/pull/1021) ([bensheldon](https://github.com/bensheldon))
47
+ - Notifier and CronManager share a 2-thread executor within the capsule [\#1018](https://github.com/bensheldon/good_job/pull/1018) ([bensheldon](https://github.com/bensheldon))
48
+ - Clarify database connections and recurring processes in README.md [\#1015](https://github.com/bensheldon/good_job/pull/1015) ([blumhardts](https://github.com/blumhardts))
49
+ - Deprecate `GoodJob::Lockable` and rename to `GoodJob::AdvisoryLockable` [\#1012](https://github.com/bensheldon/good_job/pull/1012) ([bensheldon](https://github.com/bensheldon))
50
+
3
51
  ## [v3.16.3](https://github.com/bensheldon/good_job/tree/v3.16.3) (2023-07-18)
4
52
 
5
53
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.16.2...v3.16.3)
data/README.md CHANGED
@@ -59,8 +59,8 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
59
59
  - [Timeouts](#timeouts)
60
60
  - [Optimize queues, threads, and processes](#optimize-queues-threads-and-processes)
61
61
  - [Database connections](#database-connections)
62
- - [Production setup](#production-setup)
63
- - [Queue performance with Queue Select Limit](#queue-performance-with-queue-select-limit)
62
+ - [Production setup](#production-setup)
63
+ - [Queue performance with Queue Select Limit](#queue-performance-with-queue-select-limit)
64
64
  - [Execute jobs async / in-process](#execute-jobs-async--in-process)
65
65
  - [Migrate to GoodJob from a different ActiveJob backend](#migrate-to-goodjob-from-a-different-activejob-backend)
66
66
  - [Monitor and preserve worked jobs](#monitor-and-preserve-worked-jobs)
@@ -475,7 +475,7 @@ GoodJob's concurrency control strategy for `perform_limit` is "optimistic retry
475
475
 
476
476
  GoodJob can enqueue jobs on a recurring basis that can be used as a replacement for cron.
477
477
 
478
- Cron-style jobs are run on every GoodJob process (e.g. CLI or `async` execution mode) when `config.good_job.enable_cron = true`.
478
+ Cron-style jobs can be performed by any GoodJob process (e.g., CLI or `:async` execution mode) that has `config.good_job.enable_cron` set to `true`. That is, one or more job executor processes can be configured to perform recurring jobs.
479
479
 
480
480
  GoodJob's cron uses unique indexes to ensure that only a single job is enqueued at the given time interval. In order for this to work, GoodJob must preserve cron-created job records; these records will be automatically deleted like any other preserved record.
481
481
 
@@ -484,7 +484,7 @@ Cron-format is parsed by the [`fugit`](https://github.com/floraison/fugit) gem,
484
484
  ```ruby
485
485
  # config/environments/application.rb or a specific environment e.g. production.rb
486
486
 
487
- # Enable cron in this process; e.g. only run on the first Heroku worker process
487
+ # Enable cron in this process, e.g., only run on the first Heroku worker process
488
488
  config.good_job.enable_cron = ENV['DYNO'] == 'worker.1' # or `true` or via $GOOD_JOB_ENABLE_CRON
489
489
 
490
490
  # Configure cron with a hash that has a unique key for each recurring job
@@ -954,24 +954,50 @@ Keep in mind, queue operations and management is an advanced discipline. This st
954
954
 
955
955
  ### Database connections
956
956
 
957
- Each GoodJob execution thread requires its own database connection that is automatically checked out from Rails’ connection pool. For example:
957
+ GoodJob job executor processes require the following database connections:
958
+
959
+ - 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`.
960
+ - 2 additional connections that GoodJob uses for utility functionality (e.g. LISTEN/NOTIFY, cron, etc.)
961
+ - 1 connection per subthread, if your application makes multithreaded database queries (e.g. `load_async`) within a job.
962
+
963
+ The executor process will not crash if the connections pool is exhausted, instead it will report an exception (eg. `ActiveRecord::ConnectionTimeoutError`).
964
+
965
+ When GoodJob runs in `:inline` mode (in Rails' test environment, by default), the default database pool configuration works.
966
+
967
+ ```yml
968
+ # config/database.yml
969
+
970
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
971
+ ```
972
+
973
+ When GoodJob runs in `:async` mode (in Rails's development environment, by default), the following database pool configuration works, where:
974
+
975
+ - `ENV.fetch("RAILS_MAX_THREADS", 5)` is the number of threads used by the web server
976
+ - `1` is the number of connections used by the job listener
977
+ - `2` is the number of connections used by the cron scheduler and executor
978
+ - `ENV.fetch("GOOD_JOB_MAX_THREADS", 5)` is the number of threads used to perform jobs
958
979
 
959
980
  ```yaml
960
981
  # config/database.yml
961
- pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5).to_i + 3 + ENV.fetch("GOOD_JOB_MAX_THREADS", 5).to_i %>
982
+
983
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5).to_i + 1 + 2 + ENV.fetch("GOOD_JOB_MAX_THREADS", 5).to_i %>
962
984
  ```
963
985
 
964
- To calculate the total number of the database connections you'll need:
986
+ 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.
965
987
 
966
- - 1 connection dedicated to the scheduler aka `LISTEN/NOTIFY`
967
- - 1 connection per query pool thread e.g. `--queues=mice:2;elephants:1` is 3 threads. Pool thread size defaults to `--max-threads`
968
- - (optional) 2 connections for Cron scheduler if you're running it
969
- - (optional) 1 connection per subthread, if your application makes multithreaded database queries within a job
970
- - When running `:async`, you must also add the number of threads by the webserver
988
+ ```yaml
989
+ # config/database.yml
990
+
991
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5) %>
992
+ ```
971
993
 
972
- The queue process will not crash if the connections pool is exhausted, instead it will report an exception (eg. `ActiveRecord::ConnectionTimeoutError`).
994
+ ```yaml
995
+ # config/database.yml
996
+
997
+ pool: <%= 1 + 2 + ENV.fetch("GOOD_JOB_MAX_THREADS", 5).to_i %>
998
+ ```
973
999
 
974
- #### Production setup
1000
+ ### Production setup
975
1001
 
976
1002
  When running GoodJob in a production environment, you should be mindful of:
977
1003
 
@@ -986,7 +1012,7 @@ The recommended way to monitor the queue in production is:
986
1012
  - keep an eye on the number of jobs in the queue (abnormal high number of unscheduled jobs means the queue could be underperforming)
987
1013
  - consider performance monitoring services which support the built-in Rails instrumentation (eg. Sentry, Skylight, etc.)
988
1014
 
989
- #### Queue performance with Queue Select Limit
1015
+ ### Queue performance with Queue Select Limit
990
1016
 
991
1017
  GoodJob’s advisory locking strategy uses a materialized CTE (Common Table Expression). This strategy can be non-performant when querying a very large queue of executable jobs (100,000+) because the database query must materialize all executable jobs before acquiring an advisory lock.
992
1018
 
@@ -8,7 +8,9 @@ import setupPopovers from "popovers";
8
8
  import LivePoll from "live_poll";
9
9
 
10
10
  import { Application } from "stimulus";
11
+ import ThemeController from "theme_controller";
11
12
  window.Stimulus = Application.start();
13
+ Stimulus.register("theme", ThemeController)
12
14
 
13
15
  documentReady(function() {
14
16
  renderCharts();
@@ -0,0 +1,44 @@
1
+ // hello_controller.js
2
+ import { Controller } from "stimulus"
3
+ export default class extends Controller {
4
+ static targets = [ "dropdown", "button" ]
5
+
6
+ connect() {
7
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
8
+ const theme = localStorage.getItem('good_job-theme');
9
+ if (!["light", "dark"].includes(theme)) {
10
+ this.setTheme(this.autoTheme());
11
+ }
12
+ });
13
+
14
+ this.setTheme(this.getStoredTheme() || 'light');
15
+ }
16
+
17
+ change(event) {
18
+ const theme = event.params.value;
19
+ localStorage.setItem('good_job-theme', theme);
20
+ this.setTheme(theme);
21
+ }
22
+
23
+ setTheme(theme) {
24
+ document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? this.autoTheme() : theme);
25
+
26
+ this.buttonTargets.forEach((button) => {
27
+ button.classList.remove('active');
28
+ if (button.dataset.themeValueParam === theme) {
29
+ button.classList.add('active');
30
+ }
31
+ });
32
+
33
+ const svg = this.buttonTargets.filter(b => b.matches(".active"))[0]?.querySelector('svg');
34
+ this.dropdownTarget.querySelector('svg').outerHTML = svg.outerHTML;
35
+ }
36
+
37
+ getStoredTheme() {
38
+ return localStorage.getItem('good_job-theme');
39
+ }
40
+
41
+ autoTheme() {
42
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
43
+ }
44
+ }