good_job 2.15.0 → 2.16.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b978264b509be9bd83e1e5e67f291b2889deff86c8316f876ab9def8264a7dd0
4
- data.tar.gz: 9b4172f97c1c7406d3c51ec81f926adaca801baa004aed743a8cac757bb2ce86
3
+ metadata.gz: 1811646b013e9432de87917a2be838ee634902b22ecc942bae74a7fefab82487
4
+ data.tar.gz: 14a301ce871b2761484d1c40d71dc76a64ce40131b6c4f3ff5573c1a2201ee58
5
5
  SHA512:
6
- metadata.gz: a2696f821699ea080d2b77bb7704192222e6347d1b2be7fcf7a5e049d7b8979ceea3f5236c165fb27bb17fa5f9d8c7d2e5bb863b9c7298de9efb892facb6bca7
7
- data.tar.gz: 0ab7a37d403e1bec9c0638835c903aff4a1168f33143c7c27acd87c07bf95a61c1475c3e61bea0a7590d167144761cc64b7bc81566746c854c2ae9698aa999fe
6
+ metadata.gz: f719e920a42b626b022ea6e90572344a660adf9fac9978fcde0ae98abbb0433d89a32af25f51e14a7250ffa2ffb128accc95fce9121630cc178b957f114e2fdf
7
+ data.tar.gz: 83265d3360d14d249303179d5ef506e39709ddf9fbbc87df99b42e5b6057d1e9acc0a59712e8b82f0d79df69b868a26b0f5de9ebf0e1adac2e421f0b1288b94f
data/CHANGELOG.md CHANGED
@@ -1,11 +1,52 @@
1
1
  # Changelog
2
2
 
3
+ ## [v2.16.0](https://github.com/bensheldon/good_job/tree/v2.16.0) (2022-06-17)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.15.2...v2.16.0)
6
+
7
+ **Closed issues:**
8
+
9
+ - Upgrading zeitwerk to 2.6.0 causes a warning related to good\_job [\#616](https://github.com/bensheldon/good_job/issues/616)
10
+
11
+ **Merged pull requests:**
12
+
13
+ - Allow inline executor to respect scheduled jobs; deprecate old behavior. Add `GoodJob.perform_inline` [\#615](https://github.com/bensheldon/good_job/pull/615) ([bensheldon](https://github.com/bensheldon))
14
+
15
+ ## [v2.15.2](https://github.com/bensheldon/good_job/tree/v2.15.2) (2022-06-17)
16
+
17
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.15.1...v2.15.2)
18
+
19
+ **Closed issues:**
20
+
21
+ - ActiveRecord::StatementInvalid PG::ProgramLimitExceeded: ERROR: index row size 3296 exceeds btree version 4 maximum 2704 for index [\#612](https://github.com/bensheldon/good_job/issues/612)
22
+
23
+ **Merged pull requests:**
24
+
25
+ - Zeitwerk ignore `lib/active_job` [\#617](https://github.com/bensheldon/good_job/pull/617) ([bensheldon](https://github.com/bensheldon))
26
+
27
+ ## [v2.15.1](https://github.com/bensheldon/good_job/tree/v2.15.1) (2022-05-24)
28
+
29
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.15.0...v2.15.1)
30
+
31
+ **Closed issues:**
32
+
33
+ - dashboard/engine – i18n: Wrong translation scope [\#605](https://github.com/bensheldon/good_job/issues/605)
34
+ - Concurrency not properly putting jobs in the queue [\#603](https://github.com/bensheldon/good_job/issues/603)
35
+ - Some dashboard actions have a routing error [\#602](https://github.com/bensheldon/good_job/issues/602)
36
+
37
+ **Merged pull requests:**
38
+
39
+ - Fix/i18n status scopes [\#607](https://github.com/bensheldon/good_job/pull/607) ([Jay-Schneider](https://github.com/Jay-Schneider))
40
+ - Make "Live Polling" ToC entry clickable [\#606](https://github.com/bensheldon/good_job/pull/606) ([aried3r](https://github.com/aried3r))
41
+ - Update readme explaining Concurrency implementation and how to integrate Dashboard with API-only Rails apps [\#604](https://github.com/bensheldon/good_job/pull/604) ([bensheldon](https://github.com/bensheldon))
42
+
3
43
  ## [v2.15.0](https://github.com/bensheldon/good_job/tree/v2.15.0) (2022-05-18)
4
44
 
5
45
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.14.4...v2.15.0)
6
46
 
7
47
  **Implemented enhancements:**
8
48
 
49
+ - Remove ability to destroy individual Executions from Dashboard; rename "Toggle" to "Inspect" everywhere [\#601](https://github.com/bensheldon/good_job/pull/601) ([bensheldon](https://github.com/bensheldon))
9
50
  - Adds the ability to delete jobs on the dashboard; add `cleanup_discarded_jobs` option to retain discarded jobs during cleanup [\#597](https://github.com/bensheldon/good_job/pull/597) ([TAGraves](https://github.com/TAGraves))
10
51
  - Dashboard: show more details about jobs [\#575](https://github.com/bensheldon/good_job/pull/575) ([bkeepers](https://github.com/bkeepers))
11
52
 
@@ -15,7 +56,6 @@
15
56
 
16
57
  **Merged pull requests:**
17
58
 
18
- - Remove ability to destroy individual Executions from Dashboard; rename "Toggle" to "Inspect" everywhere [\#601](https://github.com/bensheldon/good_job/pull/601) ([bensheldon](https://github.com/bensheldon))
19
59
  - Disable ActiveRecord Connection Reaper in test [\#600](https://github.com/bensheldon/good_job/pull/600) ([bensheldon](https://github.com/bensheldon))
20
60
  - Update README dashboard screenshot [\#599](https://github.com/bensheldon/good_job/pull/599) ([aried3r](https://github.com/aried3r))
21
61
 
data/README.md CHANGED
@@ -39,7 +39,10 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
39
39
  - [Configuration options](#configuration-options)
40
40
  - [Global options](#global-options)
41
41
  - [Dashboard](#dashboard)
42
+ - [API-only Rails applications](#api-only-rails-applications)
43
+ - [Live Polling](#live-polling)
42
44
  - [ActiveJob concurrency](#activejob-concurrency)
45
+ - [How concurrency controls work](#how-concurrency-controls-work)
43
46
  - [Cron-style repeating/recurring jobs](#cron-style-repeatingrecurring-jobs)
44
47
  - [Updating](#updating)
45
48
  - [Upgrading minor versions](#upgrading-minor-versions)
@@ -56,6 +59,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
56
59
  - [Execute jobs async / in-process](#execute-jobs-async--in-process)
57
60
  - [Migrate to GoodJob from a different ActiveJob backend](#migrate-to-goodjob-from-a-different-activejob-backend)
58
61
  - [Monitor and preserve worked jobs](#monitor-and-preserve-worked-jobs)
62
+ - [Write tests](#write-tests)
59
63
  - [PgBouncer compatibility](#pgbouncer-compatibility)
60
64
  - [CLI HTTP health check probes](#cli-http-health-check-probes)
61
65
  - [Contribute](#contribute)
@@ -273,6 +277,7 @@ Available configuration options are:
273
277
  - `cleanup_preserved_jobs_before_seconds_ago` (integer) number of seconds to preserve jobs when using the `$ good_job cleanup_preserved_jobs` CLI command or calling `GoodJob.cleanup_preserved_jobs`. Defaults to `86400` (1 day). Can also be set with the environment variable `GOOD_JOB_CLEANUP_PRESERVED_JOBS_BEFORE_SECONDS_AGO`. _This configuration is only used when {GoodJob.preserve_job_records} is `true`._
274
278
  - `cleanup_interval_jobs` (integer) Number of jobs a Scheduler will execute before cleaning up preserved jobs. Defaults to `nil`. Can also be set with the environment variable `GOOD_JOB_CLEANUP_INTERVAL_JOBS`.
275
279
  - `cleanup_interval_seconds` (integer) Number of seconds a Scheduler will wait before cleaning up preserved jobs. Defaults to `nil`. Can also be set with the environment variable `GOOD_JOB_CLEANUP_INTERVAL_SECONDS`.
280
+ - `inline_execution_respects_schedule` (boolean) Opt-in to future behavior of inline execution respecting scheduled jobs. Defaults to `false`.
276
281
  - `logger` ([Rails Logger](https://api.rubyonrails.org/classes/ActiveSupport/Logger.html)) lets you set a custom logger for GoodJob. It should be an instance of a Rails `Logger` (Default: `Rails.logger`).
277
282
  - `preserve_job_records` (boolean) keeps job records in your database even after jobs are completed. (Default: `false`)
278
283
  - `retry_on_unhandled_error` (boolean) causes jobs to be re-queued and retried if they raise an instance of `StandardError`. Be advised this may lead to jobs being repeated infinitely ([see below for more on retries](#retries)). Instances of `Exception`, like SIGINT, will *always* be retried, regardless of this attribute’s value. (Default: `true`)
@@ -368,6 +373,23 @@ GoodJob includes a Dashboard as a mountable `Rails::Engine`.
368
373
  end
369
374
  ```
370
375
 
376
+ #### API-only Rails applications
377
+
378
+ API-only Rails applications may not have all of the required Rack middleware for the GoodJob Dashboard to function. To re-add the middlware:
379
+
380
+ ```ruby
381
+ # config/application.rb
382
+ module MyApp
383
+ class Application < Rails::Application
384
+ #...
385
+ config.middleware.use Rack::MethodOverride
386
+ config.middleware.use ActionDispatch::Flash
387
+ config.middleware.use ActionDispatch::Cookies
388
+ config.middleware.use ActionDispatch::Session::CookieStore
389
+ end
390
+ end
391
+ ```
392
+
371
393
  #### Live Polling
372
394
 
373
395
  The Dashboard can be set to automatically refresh by checking "Live Poll" in the Dashboard header, or by setting `?poll=10` with the interval in seconds (default 30 seconds).
@@ -420,6 +442,13 @@ job = MyJob.perform_later("Alice")
420
442
  job.good_job_concurrency_key #=> "Unique-Alice"
421
443
  ```
422
444
 
445
+ #### How concurrency controls work
446
+
447
+ GoodJob's concurrency control strategy for `perform_limit` is "optimistic retry with an incremental backoff". The [code is readable](https://github.com/bensheldon/good_job/blob/main/lib/good_job/active_job_extensions/concurrency.rb).
448
+
449
+ - "Optimistic" meaning that the implementation's performance trade-off assumes that collisions are atypical (e.g. two users enqueue the same job at the same time) rather than regular (e.g. the system enqueues thousands of colliding jobs at the same time).
450
+ - "Retry with an incremental backoff" means that when `perform_limit` is exceeded, the job will raise a `GoodJob::ActiveJobExtensions::Concurrency::ConcurrencyExceededError` which is caught by a `retry_on` handler which re-schedules the job to execute in the near future with an incremental backoff.
451
+
423
452
  ### Cron-style repeating/recurring jobs
424
453
 
425
454
  GoodJob can enqueue jobs on a recurring basis that can be used as a replacement for cron.
@@ -851,6 +880,23 @@ It is also necessary to destroy these preserved jobs from the database after a c
851
880
  bundle exec good_job cleanup_preserved_jobs --before-seconds-ago=86400
852
881
  ```
853
882
 
883
+ ### Write tests
884
+
885
+ By default, GoodJob uses its inline adapter in the test environment; the inline adapter is designed for the test environment. When enquing a job with GoodJob's inline adapter, the job will be executed immediately on the current thread; unhandled exceptions will be raised.
886
+
887
+ In GoodJob 2.0, the inline adapter will execute future scheduled jobs immediately. In the next major release, GoodJob 3.0, the inline adapter will not execute future scheduled jobs and instead enqueue them in the database.
888
+
889
+ To opt into this behavior immediately set: `config.good_job.inline_execution_respects_schedule = true`
890
+
891
+ To perform jobs inline at any time, use `GoodJob.perform_inline`. For example, using time helpers within an integration test:
892
+
893
+ ```ruby
894
+ MyJob.set(wait: 10.minutes).perform_later
895
+ travel_to(15.minutes.from_now) { GoodJob.perform_inline }
896
+ ```
897
+
898
+ _Note: Rails `travel`/`travel_to` time helpers do not have millisecond precision, so you must leave at least 1 second between the schedule and time traveling for the job to be executed. This [behavior may change in Rails 7.1](https://github.com/rails/rails/pull/44088)._
899
+
854
900
  ### PgBouncer compatibility
855
901
 
856
902
  GoodJob is not compatible with PgBouncer in _transaction_ mode, but is compatible with PgBouncer's _connection_ mode. GoodJob uses connection-based advisory locks and LISTEN/NOTIFY, both of which require full database connections.
@@ -34,3 +34,8 @@
34
34
  .toast-container {
35
35
  z-index: 1;
36
36
  }
37
+
38
+ .translation_missing {
39
+ background-color: red;
40
+ color: white;
41
+ }
@@ -41,7 +41,7 @@ module GoodJob
41
41
  }.freeze
42
42
 
43
43
  def status_badge(status)
44
- content_tag :span, status_icon(status, class: "text-white") + t(status, scope: '.status'),
44
+ content_tag :span, status_icon(status, class: "text-white") + t(status, scope: 'good_job.status'),
45
45
  class: "badge rounded-pill bg-#{STATUS_COLOR.fetch(status)} d-inline-flex gap-2 ps-1 pe-3 align-items-center"
46
46
  end
47
47
 
@@ -10,7 +10,7 @@
10
10
  <% filter.states.each do |name, count| %>
11
11
  <li class="nav-item">
12
12
  <%= link_to url_for({state: name}), class: "nav-link #{"active" if params[:state] == name}" do %>
13
- <%= t(name, scope: '.status') %>
13
+ <%= t(name, scope: 'good_job.status') %>
14
14
  <span class="badge bg-primary rounded-pill <%= "bg-secondary" if count == 0 %>"><%= count %></span>
15
15
  <% end %>
16
16
  </li>
@@ -62,19 +62,48 @@ module GoodJob
62
62
  # @param timestamp [Integer, nil] the epoch time to perform the job
63
63
  # @return [GoodJob::Execution]
64
64
  def enqueue_at(active_job, timestamp)
65
+ scheduled_at = timestamp ? Time.zone.at(timestamp) : nil
66
+
67
+ if execute_inline?
68
+ future_scheduled = (scheduled_at.nil? || scheduled_at > Time.current)
69
+ will_execute_inline = !future_scheduled || (future_scheduled && !@configuration.inline_execution_respects_schedule?)
70
+ end
71
+
65
72
  execution = GoodJob::Execution.enqueue(
66
73
  active_job,
67
- scheduled_at: timestamp ? Time.zone.at(timestamp) : nil,
68
- create_with_advisory_lock: execute_inline?
74
+ scheduled_at: scheduled_at,
75
+ create_with_advisory_lock: will_execute_inline
69
76
  )
70
77
 
71
- if execute_inline?
78
+ if will_execute_inline
79
+ if future_scheduled && !@configuration.inline_execution_respects_schedule?
80
+ ActiveSupport::Deprecation.warn(<<~DEPRECATION)
81
+ In the next major release, GoodJob will not *inline* execute
82
+ future-scheduled jobs.
83
+
84
+ To opt into this behavior immediately set:
85
+ `config.good_job.inline_execution_respects_schedule = true`
86
+
87
+ To perform jobs inline at any time, use `GoodJob.perform_inline`.
88
+
89
+ For example, using time helpers within an integration test:
90
+
91
+ ```
92
+ MyJob.set(wait: 10.minutes).perform_later
93
+ travel_to(15.minutes.from_now) { GoodJob.perform_inline }
94
+ ```
95
+
96
+ Note: Rails `travel`/`travel_to` time helpers do not have millisecond
97
+ precision, so you must leave at least 1 second between the schedule
98
+ and time traveling for the job to be executed.
99
+ DEPRECATION
100
+ end
101
+
72
102
  begin
73
103
  result = execution.perform
74
104
  ensure
75
105
  execution.advisory_unlock
76
106
  end
77
-
78
107
  raise result.unhandled_error if result.unhandled_error
79
108
  else
80
109
  job_state = { queue_name: execution.queue_name }
@@ -119,6 +119,10 @@ module GoodJob
119
119
  end
120
120
  end
121
121
 
122
+ def inline_execution_respects_schedule?
123
+ !!rails_config[:inline_execution_respects_schedule]
124
+ end
125
+
122
126
  # The maximum number of future-scheduled jobs to store in memory.
123
127
  # Storing future-scheduled jobs in memory reduces execution latency
124
128
  # at the cost of increased memory usage. 10,000 stored jobs = ~20MB.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module GoodJob
3
3
  # GoodJob gem version.
4
- VERSION = '2.15.0'
4
+ VERSION = '2.16.0'
5
5
  end
data/lib/good_job.rb CHANGED
@@ -8,7 +8,9 @@ Zeitwerk::Loader.for_gem.tap do |loader|
8
8
  loader.inflector.inflect({
9
9
  "cli" => "CLI",
10
10
  })
11
- loader.ignore(File.join(File.dirname(__FILE__), "generators"))
11
+ loader.ignore("#{__dir__}/generators")
12
+ loader.ignore("#{__dir__}/active_job")
13
+ loader.push_dir("#{__dir__}/active_job/queue_adapters", namespace: ActiveJob::QueueAdapters)
12
14
  loader.setup
13
15
  end
14
16
 
@@ -151,6 +153,20 @@ module GoodJob
151
153
  end
152
154
  end
153
155
 
156
+ # Perform all queued jobs in the current thread.
157
+ # This is primarily intended for usage in a test environment.
158
+ # Unhandled job errors will be raised.
159
+ # @param queue_string [String] Queues to execute jobs from
160
+ # @return [void]
161
+ def self.perform_inline(queue_string = "*")
162
+ job_performer = JobPerformer.new(queue_string)
163
+ loop do
164
+ result = job_performer.next
165
+ break unless result
166
+ raise result.unhandled_error if result.unhandled_error
167
+ end
168
+ end
169
+
154
170
  def self._executables
155
171
  [].concat(
156
172
  CronManager.instances,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: good_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.15.0
4
+ version: 2.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sheldon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-05-18 00:00:00.000000000 Z
11
+ date: 2022-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob