good_job 1.6.0 → 1.9.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b8f0f56838ed9baa984ad7b70ece1c72009369149bb45522aa140298ff727d44
4
- data.tar.gz: a076e6f1315911e9fcacc8be7be4e87d176f6a63fd4cf8e297b8985d928074cf
3
+ metadata.gz: 00e281a3f0c203b1401da29f633584c6bb1bb050139413c1c3762fddce8d0555
4
+ data.tar.gz: c7d9e2e3e2e401d0d8872f66890be0901b33cb8d774860d4885b334d215248e8
5
5
  SHA512:
6
- metadata.gz: 6eae147e6a6f22da09c87b246735d0844e09dbaaea2e9b2cc92664ad86efef95feb8572ddafa83964009572d5c55db5eefc9f589d63820fb77fc59ec8ac4f110
7
- data.tar.gz: 3f884573f31e65c3d63c2b864a820b9e9dd5db2a71405f3514ffdd774458bb89c7b5a834878aba2a57b988cce02443fc2df8e986d09815f98784bdaa9de6b62f
6
+ metadata.gz: d3aa584ac5c42dfeae93596168195652a7d030c38e197467204ef1c1a03f5ff4187d9c3d45e5549d4c1eae739ec5859e0a664dc74c1d1a685fc8547357682f27
7
+ data.tar.gz: e420f7e40d16ef19f3392da7fd249887e94b805af976a740f76a237131dd2afcc05b4e29c616b63738d44070470a0c32ceefca808707afeab8fc7e6543d3b623
data/CHANGELOG.md CHANGED
@@ -1,6 +1,92 @@
1
1
  # Changelog
2
2
 
3
- ## [v1.6.0](https://github.com/bensheldon/good_job/tree/v1.6.0) (2021-01-21)
3
+ ## [v1.9.1](https://github.com/bensheldon/good_job/tree/v1.9.1) (2021-04-19)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.9.0...v1.9.1)
6
+
7
+ **Merged pull requests:**
8
+
9
+ - Allow to specify parent class for active record [\#238](https://github.com/bensheldon/good_job/pull/238) ([morgoth](https://github.com/morgoth))
10
+
11
+ ## [v1.9.0](https://github.com/bensheldon/good_job/tree/v1.9.0) (2021-04-16)
12
+
13
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.8.0...v1.9.0)
14
+
15
+ **Implemented enhancements:**
16
+
17
+ - Add `async_server` option to run async only in Rails web server process [\#230](https://github.com/bensheldon/good_job/pull/230) ([bensheldon](https://github.com/bensheldon))
18
+ - FreeBSD startup script [\#221](https://github.com/bensheldon/good_job/pull/221) ([lauer](https://github.com/lauer))
19
+
20
+ **Fixed bugs:**
21
+
22
+ - Fix instrumentation of GoodJob::Poller finished\_timer\_task event [\#233](https://github.com/bensheldon/good_job/pull/233) ([bensheldon](https://github.com/bensheldon))
23
+
24
+ **Closed issues:**
25
+
26
+ - Cannot run db:migrate when execution mode is :async [\#229](https://github.com/bensheldon/good_job/issues/229)
27
+ - How do you enqueue a job to be executed immediately outside of Rails \(eg. creating a new record of good\_jobs in Postgresql\)? [\#225](https://github.com/bensheldon/good_job/issues/225)
28
+ - Feature Ideas [\#220](https://github.com/bensheldon/good_job/issues/220)
29
+ - Goodjob startup script for FreeBSD [\#214](https://github.com/bensheldon/good_job/issues/214)
30
+ - Only start async mode executors when server is running [\#194](https://github.com/bensheldon/good_job/issues/194)
31
+
32
+ **Merged pull requests:**
33
+
34
+ - Move executable flags from constants to accessors on GoodJob::CLI [\#234](https://github.com/bensheldon/good_job/pull/234) ([bensheldon](https://github.com/bensheldon))
35
+ - Add custom Scheduler::TimerSet [\#232](https://github.com/bensheldon/good_job/pull/232) ([bensheldon](https://github.com/bensheldon))
36
+ - Fix assorted constant references in YARD documentation [\#231](https://github.com/bensheldon/good_job/pull/231) ([bensheldon](https://github.com/bensheldon))
37
+ - Update GH Test Matrix with latest JRuby 9.2.17.0 [\#228](https://github.com/bensheldon/good_job/pull/228) ([tedhexaflow](https://github.com/tedhexaflow))
38
+ - Update gem dependencies [\#227](https://github.com/bensheldon/good_job/pull/227) ([bensheldon](https://github.com/bensheldon))
39
+ - Remove leftover text from Readme [\#226](https://github.com/bensheldon/good_job/pull/226) ([weh](https://github.com/weh))
40
+ - Fix appraisal and bundler version CI conflicts [\#224](https://github.com/bensheldon/good_job/pull/224) ([bensheldon](https://github.com/bensheldon))
41
+ - Update GH Test Matrix with latest JRuby [\#223](https://github.com/bensheldon/good_job/pull/223) ([tedhexaflow](https://github.com/tedhexaflow))
42
+
43
+ ## [v1.8.0](https://github.com/bensheldon/good_job/tree/v1.8.0) (2021-03-04)
44
+
45
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.7.1...v1.8.0)
46
+
47
+ **Implemented enhancements:**
48
+
49
+ - Wait then stop on shutdown [\#126](https://github.com/bensheldon/good_job/issues/126)
50
+ - Add shutdown-timeout option to configure the wait for jobs to gracefully finish before stopping them [\#213](https://github.com/bensheldon/good_job/pull/213) ([bensheldon](https://github.com/bensheldon))
51
+
52
+ **Fixed bugs:**
53
+
54
+ - Ensure Job\#serialized\_params are immutable [\#218](https://github.com/bensheldon/good_job/pull/218) ([bensheldon](https://github.com/bensheldon))
55
+
56
+ **Closed issues:**
57
+
58
+ - Run GoodJob on puma boot [\#91](https://github.com/bensheldon/good_job/issues/91)
59
+ - ActiveRecord::ConnectionNotEstablished when using async mode [\#89](https://github.com/bensheldon/good_job/issues/89)
60
+
61
+ **Merged pull requests:**
62
+
63
+ - Update bundler and Appraisals so Rails HEAD is locked to Ruby version \>= 2.7 [\#219](https://github.com/bensheldon/good_job/pull/219) ([bensheldon](https://github.com/bensheldon))
64
+
65
+ ## [v1.7.1](https://github.com/bensheldon/good_job/tree/v1.7.1) (2021-01-27)
66
+
67
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.7.0...v1.7.1)
68
+
69
+ **Fixed bugs:**
70
+
71
+ - Scheduler should always push a new task on completion of previous task, regardless of available thread calculation [\#209](https://github.com/bensheldon/good_job/pull/209) ([bensheldon](https://github.com/bensheldon))
72
+
73
+ **Closed issues:**
74
+
75
+ - Unexpected behavior with max\_threads = 1 [\#208](https://github.com/bensheldon/good_job/issues/208)
76
+
77
+ **Merged pull requests:**
78
+
79
+ - Fix equality typo in development.rb of test\_app [\#207](https://github.com/bensheldon/good_job/pull/207) ([reczy](https://github.com/reczy))
80
+
81
+ ## [v1.7.0](https://github.com/bensheldon/good_job/tree/v1.7.0) (2021-01-25)
82
+
83
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.6.0...v1.7.0)
84
+
85
+ **Implemented enhancements:**
86
+
87
+ - Cache scheduled jobs in memory so they can be executed without polling [\#205](https://github.com/bensheldon/good_job/pull/205) ([bensheldon](https://github.com/bensheldon))
88
+
89
+ ## [v1.6.0](https://github.com/bensheldon/good_job/tree/v1.6.0) (2021-01-22)
4
90
 
5
91
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.5.0...v1.6.0)
6
92
 
@@ -11,7 +97,7 @@
11
97
 
12
98
  **Closed issues:**
13
99
 
14
- - Rails 6.1 & async - `queue\_parser': undefined method `first' for "\*":String \(NoMethodError\) [\#195](https://github.com/bensheldon/good_job/issues/195)
100
+ - Rails 6.1 & async - `queue_parser': undefined method `first' for "\*":String \(NoMethodError\) [\#195](https://github.com/bensheldon/good_job/issues/195)
15
101
 
16
102
  **Merged pull requests:**
17
103
 
@@ -26,6 +112,7 @@
26
112
  **Implemented enhancements:**
27
113
 
28
114
  - Create Web UI Dashboard [\#50](https://github.com/bensheldon/good_job/issues/50)
115
+ - Configure GoodJob via `Rails.application.config` instead of recommending `GoodJob::Adapter.new` [\#199](https://github.com/bensheldon/good_job/pull/199) ([bensheldon](https://github.com/bensheldon))
29
116
 
30
117
  **Closed issues:**
31
118
 
@@ -34,7 +121,6 @@
34
121
  **Merged pull requests:**
35
122
 
36
123
  - Update bundler version to 2.2.5 [\#200](https://github.com/bensheldon/good_job/pull/200) ([bensheldon](https://github.com/bensheldon))
37
- - Configure GoodJob via `Rails.application.config` instead of recommending `GoodJob::Adapter.new` [\#199](https://github.com/bensheldon/good_job/pull/199) ([bensheldon](https://github.com/bensheldon))
38
124
  - Update GH Test Matrix with minimum & latest JRuby version [\#197](https://github.com/bensheldon/good_job/pull/197) ([tedhexaflow](https://github.com/tedhexaflow))
39
125
  - Fix JRuby version number [\#193](https://github.com/bensheldon/good_job/pull/193) ([tedhexaflow](https://github.com/tedhexaflow))
40
126
 
@@ -171,7 +257,7 @@
171
257
  **Implemented enhancements:**
172
258
 
173
259
  - Preserve only failed jobs [\#136](https://github.com/bensheldon/good_job/issues/136)
174
- - Add `GoodJob.preserve\_job\_records = :on\_unhandled\_error` option to only preserve jobs that errored [\#145](https://github.com/bensheldon/good_job/pull/145) ([morgoth](https://github.com/morgoth))
260
+ - Add `GoodJob.preserve_job_records = :on_unhandled_error` option to only preserve jobs that errored [\#145](https://github.com/bensheldon/good_job/pull/145) ([morgoth](https://github.com/morgoth))
175
261
 
176
262
  **Fixed bugs:**
177
263
 
@@ -204,7 +290,7 @@
204
290
  - Update Gemspec to reflect that GoodJob is not compatible with Rails 5.1 [\#143](https://github.com/bensheldon/good_job/pull/143) ([bensheldon](https://github.com/bensheldon))
205
291
  - Prevent jobs hanging [\#141](https://github.com/bensheldon/good_job/pull/141) ([morgoth](https://github.com/morgoth))
206
292
  - Add explicit require\_paths to gemspec for engine [\#134](https://github.com/bensheldon/good_job/pull/134) ([bensheldon](https://github.com/bensheldon))
207
- - Use `connection.quote\_table\_name` and add spacing for SQL concatenation [\#124](https://github.com/bensheldon/good_job/pull/124) ([bensheldon](https://github.com/bensheldon))
293
+ - Use `connection.quote_table_name` and add spacing for SQL concatenation [\#124](https://github.com/bensheldon/good_job/pull/124) ([bensheldon](https://github.com/bensheldon))
208
294
 
209
295
  **Closed issues:**
210
296
 
@@ -230,7 +316,7 @@
230
316
 
231
317
  **Implemented enhancements:**
232
318
 
233
- - Add environment variable to mirror `cleanup\_preserved\_jobs --before-seconds-ago=SECONDS` [\#110](https://github.com/bensheldon/good_job/issues/110)
319
+ - Add environment variable to mirror `cleanup_preserved_jobs --before-seconds-ago=SECONDS` [\#110](https://github.com/bensheldon/good_job/issues/110)
234
320
  - Allow env variable config for cleanups [\#114](https://github.com/bensheldon/good_job/pull/114) ([gadimbaylisahil](https://github.com/gadimbaylisahil))
235
321
 
236
322
  **Fixed bugs:**
@@ -281,7 +367,7 @@
281
367
 
282
368
  **Closed issues:**
283
369
 
284
- - Add test for `rails g good\_job:install` [\#57](https://github.com/bensheldon/good_job/issues/57)
370
+ - Add test for `rails g good_job:install` [\#57](https://github.com/bensheldon/good_job/issues/57)
285
371
 
286
372
  **Merged pull requests:**
287
373
 
@@ -289,7 +375,7 @@
289
375
  - Run CI tests on Ruby 2.5, 2.6, and 2.7 [\#101](https://github.com/bensheldon/good_job/pull/101) ([arku](https://github.com/arku))
290
376
  - Fix Ruby 2.7 keyword arguments warning [\#98](https://github.com/bensheldon/good_job/pull/98) ([arku](https://github.com/arku))
291
377
  - Remove executor/reloader for less interlocking [\#97](https://github.com/bensheldon/good_job/pull/97) ([sj26](https://github.com/sj26))
292
- - Add test for `rails g good\_job:install` [\#94](https://github.com/bensheldon/good_job/pull/94) ([arku](https://github.com/arku))
378
+ - Add test for `rails g good_job:install` [\#94](https://github.com/bensheldon/good_job/pull/94) ([arku](https://github.com/arku))
293
379
 
294
380
  ## [v1.2.1](https://github.com/bensheldon/good_job/tree/v1.2.1) (2020-08-21)
295
381
 
@@ -496,7 +582,7 @@
496
582
  - Update Github Action Workflow for Backlog Project Board [\#35](https://github.com/bensheldon/good_job/pull/35) ([bensheldon](https://github.com/bensheldon))
497
583
  - Add configuration options to good\_job executable [\#33](https://github.com/bensheldon/good_job/pull/33) ([bensheldon](https://github.com/bensheldon))
498
584
  - Extract Job querying behavior out of Scheduler [\#31](https://github.com/bensheldon/good_job/pull/31) ([bensheldon](https://github.com/bensheldon))
499
- - Allow configuration of Rails queue adapter with `:good\_job` [\#28](https://github.com/bensheldon/good_job/pull/28) ([bensheldon](https://github.com/bensheldon))
585
+ - Allow configuration of Rails queue adapter with `:good_job` [\#28](https://github.com/bensheldon/good_job/pull/28) ([bensheldon](https://github.com/bensheldon))
500
586
 
501
587
  ## [v0.5.0](https://github.com/bensheldon/good_job/tree/v0.5.0) (2020-07-13)
502
588
 
data/README.md CHANGED
@@ -36,7 +36,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
36
36
  - [`good_job start`](#good_job-start)
37
37
  - [`good_job cleanup_preserved_jobs`](#good_job-cleanup_preserved_jobs)
38
38
  - [Configuration options](#configuration-options)
39
- - [Global options](#global-options)pter
39
+ - [Global options](#global-options)
40
40
  - [Dashboard](#dashboard)
41
41
  - [Go deeper](#go-deeper)
42
42
  - [Exceptions, retries, and reliability](#exceptions-retries-and-reliability)
@@ -119,10 +119,10 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
119
119
  - GoodJob can also be configured to execute jobs within the web server process to save on resources. This is useful for low-workloads when economy is paramount.
120
120
 
121
121
  ```
122
- $ GOOD_JOB_EXECUTION_MODE=async rails server
122
+ $ GOOD_JOB_EXECUTION_MODE=async_server rails server
123
123
  ```
124
124
 
125
- Additional configuration is likely necessary, see the reference below for async configuration.
125
+ Additional configuration is likely necessary, see the reference below for f configuration.
126
126
 
127
127
  ## Compatibility
128
128
 
@@ -149,11 +149,13 @@ Usage:
149
149
  good_job start
150
150
 
151
151
  Options:
152
- [--max-threads=COUNT] # Maximum number of threads to use for working jobs. (env var: GOOD_JOB_MAX_THREADS, default: 5)
153
- [--queues=QUEUE_LIST] # Queues to work from. (env var: GOOD_JOB_QUEUES, default: *)
154
- [--poll-interval=SECONDS] # Interval between polls for available jobs in seconds (env var: GOOD_JOB_POLL_INTERVAL, default: 1)
155
- [--daemonize] # Run as a background daemon (default: false)
156
- [--pidfile=PIDFILE] # Path to write daemonized Process ID (env var: GOOD_JOB_PIDFILE, default: tmp/pids/good_job.pid)
152
+ [--max-threads=COUNT] # Maximum number of threads to use for working jobs. (env var: GOOD_JOB_MAX_THREADS, default: 5)
153
+ [--queues=QUEUE_LIST] # Queues to work from. (env var: GOOD_JOB_QUEUES, default: *)
154
+ [--poll-interval=SECONDS] # Interval between polls for available jobs in seconds (env var: GOOD_JOB_POLL_INTERVAL, default: 1)
155
+ [--max-cache=COUNT] # Maximum number of scheduled jobs to cache in memory (env var: GOOD_JOB_MAX_CACHE, default: 10000)
156
+ [--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))
157
+ [--daemonize] # Run as a background daemon (default: false)
158
+ [--pidfile=PIDFILE] # Path to write daemonized Process ID (env var: GOOD_JOB_PIDFILE, default: tmp/pids/good_job.pid)
157
159
 
158
160
  Executes queued jobs.
159
161
 
@@ -204,15 +206,18 @@ Additional configuration can be provided via `config.good_job.OPTION = ...` for
204
206
  config.active_job.queue_adapter = :good_job
205
207
 
206
208
  # Configure options individually...
207
- config.good_job.execution_mode = :async
209
+ config.good_job.execution_mode = :async_server
208
210
  config.good_job.max_threads = 5
209
211
  config.good_job.poll_interval = 30 # seconds
212
+ config.good_job.shutdown_timeout = 25 # seconds
213
+
210
214
 
211
215
  # ...or all at once.
212
216
  config.good_job = {
213
- execution_mode: :async,
217
+ execution_mode: :async_server,
214
218
  max_threads: 5,
215
219
  poll_interval: 30,
220
+ shutdown_timeout: 25,
216
221
  }
217
222
  ```
218
223
 
@@ -221,10 +226,13 @@ Available configuration options are:
221
226
  - `execution_mode` (symbol) specifies how and where jobs should be executed. You can also set this with the environment variable `GOOD_JOB_EXECUTION_MODE`. It can be any one of:
222
227
  - `:inline` executes jobs immediately in whatever process queued them (usually the web server process). This should only be used in test and development environments.
223
228
  - `:external` causes the adapter to enqueue jobs, but not execute them. When using this option (the default for production environments), you’ll need to use the command-line tool to actually execute your jobs.
224
- - `:async` causes the adapter to execute you jobs in separate threads in whatever process queued them (usually the web process). This is akin to running the command-line tool’s code inside your web server. It can be more economical for small workloads (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.
225
- - `max_threads` (integer) sets the maximum number of threads to use when `execution_mode` is set to `:async`. You can also set this with the environment variable `GOOD_JOB_MAX_THREADS`.
226
- - `queues` (string) determines which queues to execute jobs from when `execution_mode` is set to `:async`. See the description of `good_job start` for more details on the format of this string. You can also set this with the environment variable `GOOD_JOB_QUEUES`.
227
- - `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`.
229
+ - `:async_server` executes jobs in separate threads within the Rails webserver 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 webserver, jobs will execute in `:external` mode to ensure jobs are not executed within `rails console`, `rails db:migrate`, `rails assets:prepare`, etc.
230
+ - `:async` executes jobs in separate threads in _any_ Rails process.
231
+ - `max_threads` (integer) sets the maximum number of threads to use when `execution_mode` is set to `:async` or `:async_server`. You can also set this with the environment variable `GOOD_JOB_MAX_THREADS`.
232
+ - `queues` (string) determines which queues to execute jobs from when `execution_mode` is set to `:async` or `:async_server`. See the description of `good_job start` for more details on the format of this string. You can also set this with the environment variable `GOOD_JOB_QUEUES`.
233
+ - `poll_interval` (integer) sets the number of seconds between polls for jobs when `execution_mode` is set to `:async` or `:async_server`. You can also set this with the environment variable `GOOD_JOB_POLL_INTERVAL`.
234
+ - `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`.
235
+ - `shutdown_timeout` (float) 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`.
228
236
 
229
237
  By default, GoodJob configures the following execution modes per environment:
230
238
 
@@ -247,6 +255,7 @@ config.good_job.execution_mode = :external
247
255
 
248
256
  Good Job’s general behavior can also be configured via several attributes directly on the `GoodJob` module:
249
257
 
258
+ - **`GoodJob.active_record_parent_class`** (string) The ActiveRecord parent class inherited by GoodJob's ActiveRecord model `GoodJob::Job` (defaults to `"ActiveRecord::Base"`). Configure this 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. _The value must be a String to avoid premature initialization of ActiveRecord._
250
259
  - **`GoodJob.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`.
251
260
  - **`GoodJob.preserve_job_records`** (boolean) keeps job records in your database even after jobs are completed. (Default: `false`)
252
261
  - **`GoodJob.retry_on_unhandled_error`** (boolean) causes jobs to be re-queued and retried if they raise an instance of `StandardError`. Instances of `Exception`, like SIGINT, will *always* be retried, regardless of this attribute’s value. (Default: `true`)
@@ -256,6 +265,7 @@ You’ll generally want to configure these in `config/initializers/good_job.rb`,
256
265
 
257
266
  ```ruby
258
267
  # config/initializers/good_job.rb
268
+ GoodJob.active_record_parent_class = "ApplicationRecord"
259
269
  GoodJob.preserve_job_records = true
260
270
  GoodJob.retry_on_unhandled_error = false
261
271
  GoodJob.on_thread_error = -> (exception) { Raven.capture_exception(exception) }
@@ -478,11 +488,11 @@ GoodJob can execute jobs "async" in the same process as the webserver (e.g. `bin
478
488
  config.active_job.queue_adapter = :good_job
479
489
 
480
490
  # To change the execution mode
481
- config.good_job.execution_mode = :async
491
+ config.good_job.execution_mode = :async_server
482
492
 
483
493
  # Or with more configuration
484
494
  config.good_job = {
485
- execution_mode: :async,
495
+ execution_mode: :async_server,
486
496
  max_threads: 4,
487
497
  poll_interval: 30
488
498
  }
@@ -491,7 +501,7 @@ GoodJob can execute jobs "async" in the same process as the webserver (e.g. `bin
491
501
  - Or, with environment variables:
492
502
 
493
503
  ```bash
494
- $ GOOD_JOB_EXECUTION_MODE=async GOOD_JOB_MAX_THREADS=4 GOOD_JOB_POLL_INTERVAL=30 bin/rails server
504
+ $ GOOD_JOB_EXECUTION_MODE=async_server GOOD_JOB_MAX_THREADS=4 GOOD_JOB_POLL_INTERVAL=30 bin/rails server
495
505
  ```
496
506
 
497
507
  Depending on your application configuration, you may need to take additional steps:
data/exe/good_job CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'good_job/cli'
3
- GOOD_JOB_LOG_TO_STDOUT = true
3
+
4
+ GoodJob::CLI.within_exe = true
5
+ GoodJob::CLI.log_to_stdout = true
4
6
  GoodJob::CLI.start(ARGV)
@@ -2,10 +2,6 @@ module ActiveJob # :nodoc:
2
2
  module QueueAdapters # :nodoc:
3
3
  # See {GoodJob::Adapter} for details.
4
4
  class GoodJobAdapter < GoodJob::Adapter
5
- def initialize(**options)
6
- configuration = GoodJob::Configuration.new(options, env: ENV)
7
- super(**options.merge(execution_mode: configuration.rails_execution_mode))
8
- end
9
5
  end
10
6
  end
11
7
  end
data/lib/good_job.rb CHANGED
@@ -17,6 +17,15 @@ require "good_job/railtie"
17
17
  #
18
18
  # +GoodJob+ is the top-level namespace and exposes configuration attributes.
19
19
  module GoodJob
20
+ # @!attribute [rw] active_record_parent_class
21
+ # @!scope class
22
+ # The ActiveRecord parent class inherited by +GoodJob::Job+ (default: +ActiveRecord::Base+).
23
+ # Use this when using multiple databases or other custom ActiveRecord configuration.
24
+ # @return [ActiveRecord::Base]
25
+ # @example Change the base class:
26
+ # GoodJob.active_record_parent_class = "CustomApplicationRecord"
27
+ mattr_accessor :active_record_parent_class, default: "ActiveRecord::Base"
28
+
20
29
  # @!attribute [rw] logger
21
30
  # @!scope class
22
31
  # The logger used by GoodJob (default: +Rails.logger+).
@@ -78,15 +87,26 @@ module GoodJob
78
87
  # See the {file:README.md#executing-jobs-async--in-process} for more explanation and examples.
79
88
  # @param wait [Boolean] whether to wait for shutdown
80
89
  # @return [void]
81
- def self.shutdown(wait: true)
82
- Notifier.instances.each { |notifier| notifier.shutdown(wait: wait) }
83
- Scheduler.instances.each { |scheduler| scheduler.shutdown(wait: wait) }
90
+ def self.shutdown(timeout: -1, wait: nil)
91
+ timeout = if wait.present?
92
+ ActiveSupport::Deprecation.warn(
93
+ "Using `GoodJob.shutdown` with `wait:` kwarg is deprecated; use `timeout:` kwarg instead e.g. GoodJob.shutdown(timeout: #{wait ? '-1' : 'nil'})"
94
+ )
95
+ wait ? -1 : nil
96
+ else
97
+ timeout
98
+ end
99
+
100
+ executables = Array(Notifier.instances) + Array(Poller.instances) + Array(Scheduler.instances)
101
+ _shutdown_all(executables, timeout: timeout)
84
102
  end
85
103
 
86
104
  # Tests whether jobs have stopped executing.
87
105
  # @return [Boolean] whether background threads are shut down
88
106
  def self.shutdown?
89
- Notifier.instances.all?(&:shutdown?) && Scheduler.instances.all?(&:shutdown?)
107
+ Notifier.instances.all?(&:shutdown?) &&
108
+ Poller.instances.all?(&:shutdown?) &&
109
+ Scheduler.instances.all?(&:shutdown?)
90
110
  end
91
111
 
92
112
  # Stops and restarts executing jobs.
@@ -95,9 +115,25 @@ module GoodJob
95
115
  # For example, you should use +shutdown+ and +restart+ when using async execution mode with Puma.
96
116
  # See the {file:README.md#executing-jobs-async--in-process} for more explanation and examples.
97
117
  # @return [void]
98
- def self.restart
99
- Notifier.instances.each(&:restart)
100
- Scheduler.instances.each(&:restart)
118
+ def self.restart(timeout: -1)
119
+ executables = Array(Notifier.instances) + Array(Poller.instances) + Array(Scheduler.instances)
120
+ _shutdown_all(executables, :restart, timeout: timeout)
121
+ end
122
+
123
+ # Sends +#shutdown+ or +#restart+ to executable objects ({GoodJob::Notifier}, {GoodJob::Poller}, {GoodJob::Scheduler})
124
+ # @param executables [Array<(Notifier, Poller, Scheduler)>] Objects to shut down.
125
+ # @param method_name [:symbol] Method to call, e.g. +:shutdown+ or +:restart+.
126
+ # @param timeout [nil,Numeric]
127
+ # @return [void]
128
+ def self._shutdown_all(executables, method_name = :shutdown, timeout: -1)
129
+ if timeout.positive?
130
+ executables.each { |executable| executable.send(method_name, timeout: nil) }
131
+
132
+ stop_at = Time.current + timeout
133
+ executables.each { |executable| executable.send(method_name, timeout: [stop_at - Time.current, 0].max) }
134
+ else
135
+ executables.each { |executable| executable.send(method_name, timeout: timeout) }
136
+ end
101
137
  end
102
138
 
103
139
  ActiveSupport.run_load_hooks(:good_job, self)
@@ -4,13 +4,15 @@ module GoodJob
4
4
  #
5
5
  class Adapter
6
6
  # Valid execution modes.
7
- EXECUTION_MODES = [:async, :external, :inline].freeze
7
+ EXECUTION_MODES = [:async, :async_server, :external, :inline].freeze
8
8
 
9
9
  # @param execution_mode [nil, Symbol] specifies how and where jobs should be executed. You can also set this with the environment variable +GOOD_JOB_EXECUTION_MODE+.
10
10
  #
11
11
  # - +:inline+ executes jobs immediately in whatever process queued them (usually the web server process). This should only be used in test and development environments.
12
12
  # - +:external+ causes the adapter to enqueue jobs, but not execute them. When using this option (the default for production environments), you'll need to use the command-line tool to actually execute your jobs.
13
- # - +:async+ causes the adapter to execute you jobs in separate threads in whatever process queued them (usually the web process). This is akin to running the command-line tool's code inside your web server. It can be more economical for small workloads (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.
13
+ # - +:async_server+ executes jobs in separate threads within the Rails webserver 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.
14
+ # When not in the Rails webserver, jobs will execute in +:external+ mode to ensure jobs are not executed within `rails console`, `rails db:migrate`, `rails assets:prepare`, etc.
15
+ # - +:async+ executes jobs in any Rails process.
14
16
  #
15
17
  # The default value depends on the Rails environment:
16
18
  #
@@ -38,7 +40,7 @@ module GoodJob
38
40
  DEPRECATION
39
41
  end
40
42
 
41
- configuration = GoodJob::Configuration.new(
43
+ @configuration = GoodJob::Configuration.new(
42
44
  {
43
45
  execution_mode: execution_mode,
44
46
  queues: queues,
@@ -46,14 +48,12 @@ module GoodJob
46
48
  poll_interval: poll_interval,
47
49
  }
48
50
  )
51
+ @configuration.validate!
49
52
 
50
- @execution_mode = configuration.execution_mode
51
- raise ArgumentError, "execution_mode: must be one of #{EXECUTION_MODES.join(', ')}." unless EXECUTION_MODES.include?(@execution_mode)
52
-
53
- if @execution_mode == :async # rubocop:disable Style/GuardClause
53
+ if execute_async? # rubocop:disable Style/GuardClause
54
54
  @notifier = GoodJob::Notifier.new
55
- @poller = GoodJob::Poller.new(poll_interval: configuration.poll_interval)
56
- @scheduler = GoodJob::Scheduler.from_configuration(configuration)
55
+ @poller = GoodJob::Poller.new(poll_interval: @configuration.poll_interval)
56
+ @scheduler = GoodJob::Scheduler.from_configuration(@configuration, warm_cache_on_initialize: Rails.application.initialized?)
57
57
  @notifier.recipients << [@scheduler, :create_thread]
58
58
  @poller.recipients << [@scheduler, :create_thread]
59
59
  end
@@ -85,37 +85,72 @@ module GoodJob
85
85
  ensure
86
86
  good_job.advisory_unlock
87
87
  end
88
- end
88
+ else
89
+ job_state = { queue_name: good_job.queue_name }
90
+ job_state[:scheduled_at] = good_job.scheduled_at if good_job.scheduled_at
89
91
 
90
- executed_locally = execute_async? && @scheduler.create_thread(queue_name: good_job.queue_name)
91
- Notifier.notify(queue_name: good_job.queue_name) unless executed_locally
92
+ executed_locally = execute_async? && @scheduler.create_thread(job_state)
93
+ Notifier.notify(job_state) unless executed_locally
94
+ end
92
95
 
93
96
  good_job
94
97
  end
95
98
 
96
- # Gracefully stop processing jobs.
97
- # Waits for termination by default.
98
- # @param wait [Boolean] Whether to wait for shut down.
99
+ # Shut down the thread pool executors.
100
+ # @param timeout [nil, Numeric] Seconds to wait for active threads.
101
+ #
102
+ # * +nil+, the scheduler will trigger a shutdown but not wait for it to complete.
103
+ # * +-1+, the scheduler will wait until the shutdown is complete.
104
+ # * +0+, the scheduler will immediately shutdown and stop any threads.
105
+ # * A positive number will wait that many seconds before stopping any remaining active threads.
106
+ # @param wait [Boolean] Deprecated. Use +timeout:+ instead.
99
107
  # @return [void]
100
- def shutdown(wait: true)
101
- @notifier&.shutdown(wait: wait)
102
- @poller&.shutdown(wait: wait)
103
- @scheduler&.shutdown(wait: wait)
108
+ def shutdown(timeout: :default, wait: nil)
109
+ timeout = if wait.present?
110
+ ActiveSupport::Deprecation.warn(
111
+ "Using `GoodJob::Adapter.shutdown` with `wait:` kwarg is deprecated; use `timeout:` kwarg instead e.g. GoodJob::Adapter.shutdown(timeout: #{wait ? '-1' : 'nil'})"
112
+ )
113
+ wait ? -1 : nil
114
+ else
115
+ timeout
116
+ end
117
+
118
+ timeout = if timeout == :default
119
+ @configuration.shutdown_timeout
120
+ else
121
+ timeout
122
+ end
123
+
124
+ executables = [@notifier, @poller, @scheduler].compact
125
+ GoodJob._shutdown_all(executables, timeout: timeout)
104
126
  end
105
127
 
106
128
  # Whether in +:async+ execution mode.
107
129
  def execute_async?
108
- @execution_mode == :async
130
+ @configuration.execution_mode == :async ||
131
+ @configuration.execution_mode == :async_server && in_server_process?
109
132
  end
110
133
 
111
134
  # Whether in +:external+ execution mode.
112
135
  def execute_externally?
113
- @execution_mode == :external
136
+ @configuration.execution_mode == :external ||
137
+ @configuration.execution_mode == :async_server && !in_server_process?
114
138
  end
115
139
 
116
140
  # Whether in +:inline+ execution mode.
117
141
  def execute_inline?
118
- @execution_mode == :inline
142
+ @configuration.execution_mode == :inline
143
+ end
144
+
145
+ private
146
+
147
+ # Whether running in a web server process.
148
+ def in_server_process?
149
+ return @_in_server_process if defined? @_in_server_process
150
+
151
+ @_in_server_process = Rails.const_defined?('Server') ||
152
+ caller.grep(%r{config.ru}).any? || # EXAMPLE: config.ru:3:in `block in <main>' OR config.ru:3:in `new_from_string'
153
+ (Concurrent.on_jruby? && caller.grep(%r{jruby/rack/rails_booter}).any?) # EXAMPLE: uri:classloader:/jruby/rack/rails_booter.rb:83:in `load_environment'
119
154
  end
120
155
  end
121
156
  end