good_job 3.16.3 → 3.17.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }