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 +4 -4
- data/CHANGELOG.md +95 -9
- data/README.md +27 -17
- data/exe/good_job +3 -1
- data/lib/active_job/queue_adapters/good_job_adapter.rb +0 -4
- data/lib/good_job.rb +43 -7
- data/lib/good_job/adapter.rb +57 -22
- data/lib/good_job/cli.rb +26 -7
- data/lib/good_job/configuration.rb +62 -39
- data/lib/good_job/job.rb +26 -1
- data/lib/good_job/job_performer.rb +11 -0
- data/lib/good_job/lockable.rb +2 -2
- data/lib/good_job/multi_scheduler.rb +12 -7
- data/lib/good_job/notifier.rb +44 -35
- data/lib/good_job/poller.rb +32 -21
- data/lib/good_job/railtie.rb +4 -0
- data/lib/good_job/scheduler.rb +156 -51
- data/lib/good_job/version.rb +1 -1
- metadata +3 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00e281a3f0c203b1401da29f633584c6bb1bb050139413c1c3762fddce8d0555
|
4
|
+
data.tar.gz: c7d9e2e3e2e401d0d8872f66890be0901b33cb8d774860d4885b334d215248e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3aa584ac5c42dfeae93596168195652a7d030c38e197467204ef1c1a03f5ff4187d9c3d45e5549d4c1eae739ec5859e0a664dc74c1d1a685fc8547357682f27
|
7
|
+
data.tar.gz: e420f7e40d16ef19f3392da7fd249887e94b805af976a740f76a237131dd2afcc05b4e29c616b63738d44070470a0c32ceefca808707afeab8fc7e6543d3b623
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,92 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## [v1.
|
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 - `
|
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.
|
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.
|
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 `
|
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
|
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
|
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 `:
|
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)
|
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=
|
122
|
+
$ GOOD_JOB_EXECUTION_MODE=async_server rails server
|
123
123
|
```
|
124
124
|
|
125
|
-
Additional configuration is likely necessary, see the reference below for
|
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]
|
153
|
-
[--queues=QUEUE_LIST]
|
154
|
-
[--poll-interval=SECONDS]
|
155
|
-
[--
|
156
|
-
[--
|
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 = :
|
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: :
|
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
|
-
- `:
|
225
|
-
- `
|
226
|
-
- `
|
227
|
-
- `
|
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 = :
|
491
|
+
config.good_job.execution_mode = :async_server
|
482
492
|
|
483
493
|
# Or with more configuration
|
484
494
|
config.good_job = {
|
485
|
-
execution_mode: :
|
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=
|
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
@@ -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:
|
82
|
-
|
83
|
-
|
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?) &&
|
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.
|
100
|
-
|
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)
|
data/lib/good_job/adapter.rb
CHANGED
@@ -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
|
-
# - +:
|
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
|
-
|
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
|
-
|
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
|
-
|
91
|
-
|
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
|
-
#
|
97
|
-
#
|
98
|
-
#
|
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:
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|