good_job 1.7.1 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -10
- data/README.md +11 -6
- data/lib/good_job.rb +34 -7
- data/lib/good_job/adapter.rb +33 -15
- data/lib/good_job/cli.rb +6 -3
- data/lib/good_job/configuration.rb +24 -10
- data/lib/good_job/job.rb +2 -0
- data/lib/good_job/job_performer.rb +3 -2
- data/lib/good_job/multi_scheduler.rb +11 -6
- data/lib/good_job/notifier.rb +41 -32
- data/lib/good_job/poller.rb +31 -20
- data/lib/good_job/scheduler.rb +71 -65
- data/lib/good_job/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff879dc7996d0f02055d1b61cff803a6ba24a5e0ec5441b8c81e3b7b1730fe63
|
4
|
+
data.tar.gz: 988e726ed6b8ba20d202bc86d7a21645ac8d08d2cf32b86aad258cfacf92e7db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f268aa3249af67cad76da907afaa698726ab8b0ead6f004af1f13cd5fcf6e93b5f39b34540b3207252eaaac107f5f5d59bf0277ad76417a4ad7bd08ee811aaaf
|
7
|
+
data.tar.gz: 464a66b3dee0bfd771a5b28527cff4dffd0e704a9a301effc40ebec8ebaf1702b8180c0b97b2d78939913b1439f22aa25f9c434f0ae9ae5c88b136d07b4dd094
|
data/CHANGELOG.md
CHANGED
@@ -1,23 +1,48 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v1.8.0](https://github.com/bensheldon/good_job/tree/v1.8.0) (2021-03-03)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.7.1...v1.8.0)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Wait then stop on shutdown [\#126](https://github.com/bensheldon/good_job/issues/126)
|
10
|
+
- 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))
|
11
|
+
|
12
|
+
**Fixed bugs:**
|
13
|
+
|
14
|
+
- Ensure Job\#serialized\_params are immutable [\#218](https://github.com/bensheldon/good_job/pull/218) ([bensheldon](https://github.com/bensheldon))
|
15
|
+
|
16
|
+
**Closed issues:**
|
17
|
+
|
18
|
+
- Run GoodJob on puma boot [\#91](https://github.com/bensheldon/good_job/issues/91)
|
19
|
+
- ActiveRecord::ConnectionNotEstablished when using async mode [\#89](https://github.com/bensheldon/good_job/issues/89)
|
20
|
+
|
21
|
+
**Merged pull requests:**
|
22
|
+
|
23
|
+
- 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))
|
24
|
+
|
3
25
|
## [v1.7.1](https://github.com/bensheldon/good_job/tree/v1.7.1) (2021-01-27)
|
4
26
|
|
5
27
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.7.0...v1.7.1)
|
6
28
|
|
29
|
+
**Fixed bugs:**
|
30
|
+
|
31
|
+
- 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))
|
32
|
+
|
7
33
|
**Closed issues:**
|
8
34
|
|
9
35
|
- Unexpected behavior with max\_threads = 1 [\#208](https://github.com/bensheldon/good_job/issues/208)
|
10
36
|
|
11
37
|
**Merged pull requests:**
|
12
38
|
|
13
|
-
- 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))
|
14
39
|
- Fix equality typo in development.rb of test\_app [\#207](https://github.com/bensheldon/good_job/pull/207) ([reczy](https://github.com/reczy))
|
15
40
|
|
16
41
|
## [v1.7.0](https://github.com/bensheldon/good_job/tree/v1.7.0) (2021-01-25)
|
17
42
|
|
18
43
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.6.0...v1.7.0)
|
19
44
|
|
20
|
-
**
|
45
|
+
**Implemented enhancements:**
|
21
46
|
|
22
47
|
- 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))
|
23
48
|
|
@@ -47,6 +72,7 @@
|
|
47
72
|
**Implemented enhancements:**
|
48
73
|
|
49
74
|
- Create Web UI Dashboard [\#50](https://github.com/bensheldon/good_job/issues/50)
|
75
|
+
- 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))
|
50
76
|
|
51
77
|
**Closed issues:**
|
52
78
|
|
@@ -55,7 +81,6 @@
|
|
55
81
|
**Merged pull requests:**
|
56
82
|
|
57
83
|
- Update bundler version to 2.2.5 [\#200](https://github.com/bensheldon/good_job/pull/200) ([bensheldon](https://github.com/bensheldon))
|
58
|
-
- 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))
|
59
84
|
- Update GH Test Matrix with minimum & latest JRuby version [\#197](https://github.com/bensheldon/good_job/pull/197) ([tedhexaflow](https://github.com/tedhexaflow))
|
60
85
|
- Fix JRuby version number [\#193](https://github.com/bensheldon/good_job/pull/193) ([tedhexaflow](https://github.com/tedhexaflow))
|
61
86
|
|
@@ -74,6 +99,7 @@
|
|
74
99
|
**Merged pull requests:**
|
75
100
|
|
76
101
|
- Add missing YARD docs and Dashboard screenshot [\#191](https://github.com/bensheldon/good_job/pull/191) ([bensheldon](https://github.com/bensheldon))
|
102
|
+
- Update all Lockable queries to use exec\_query instead of execute; clear async\_exec results [\#189](https://github.com/bensheldon/good_job/pull/189) ([bensheldon](https://github.com/bensheldon))
|
77
103
|
|
78
104
|
## [v1.4.0](https://github.com/bensheldon/good_job/tree/v1.4.0) (2020-12-31)
|
79
105
|
|
@@ -100,7 +126,6 @@
|
|
100
126
|
**Merged pull requests:**
|
101
127
|
|
102
128
|
- Run tests with Rails default configuration to enable Zeitwerk [\#190](https://github.com/bensheldon/good_job/pull/190) ([bensheldon](https://github.com/bensheldon))
|
103
|
-
- Update all Lockable queries to use exec\_query instead of execute; clear async\_exec results [\#189](https://github.com/bensheldon/good_job/pull/189) ([bensheldon](https://github.com/bensheldon))
|
104
129
|
- Have Lockable\#advisory\_locked? directly query pg\_locks table [\#188](https://github.com/bensheldon/good_job/pull/188) ([bensheldon](https://github.com/bensheldon))
|
105
130
|
- Update development gems, including Rails v6.1 and Rails HEAD [\#186](https://github.com/bensheldon/good_job/pull/186) ([bensheldon](https://github.com/bensheldon))
|
106
131
|
- Update Appraisals for Rails 6.1 [\#183](https://github.com/bensheldon/good_job/pull/183) ([bensheldon](https://github.com/bensheldon))
|
@@ -114,7 +139,6 @@
|
|
114
139
|
|
115
140
|
- Ensure advisory lock CTE is MATERIALIZED on Postgres v12+ [\#179](https://github.com/bensheldon/good_job/pull/179) ([bensheldon](https://github.com/bensheldon))
|
116
141
|
- Ensure that deleted jobs are unlocked [\#178](https://github.com/bensheldon/good_job/pull/178) ([bensheldon](https://github.com/bensheldon))
|
117
|
-
- Fix job ordering for Rails 6.1 [\#174](https://github.com/bensheldon/good_job/pull/174) ([morgoth](https://github.com/morgoth))
|
118
142
|
|
119
143
|
**Closed issues:**
|
120
144
|
|
@@ -129,6 +153,10 @@
|
|
129
153
|
|
130
154
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.3...v1.3.4)
|
131
155
|
|
156
|
+
**Fixed bugs:**
|
157
|
+
|
158
|
+
- Fix job ordering for Rails 6.1 [\#174](https://github.com/bensheldon/good_job/pull/174) ([morgoth](https://github.com/morgoth))
|
159
|
+
|
132
160
|
## [v1.3.3](https://github.com/bensheldon/good_job/tree/v1.3.3) (2020-12-01)
|
133
161
|
|
134
162
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.2...v1.3.3)
|
@@ -268,7 +296,6 @@
|
|
268
296
|
- Have YARD render markdown files with GFM \(Github Flavored Markdown\) [\#113](https://github.com/bensheldon/good_job/pull/113) ([bensheldon](https://github.com/bensheldon))
|
269
297
|
- Add markdownlint to lint readme [\#109](https://github.com/bensheldon/good_job/pull/109) ([bensheldon](https://github.com/bensheldon))
|
270
298
|
- Remove unused method in PgLocks [\#107](https://github.com/bensheldon/good_job/pull/107) ([gadimbaylisahil](https://github.com/gadimbaylisahil))
|
271
|
-
- Re-organize Readme: frontload configuration, add Table of Contents [\#106](https://github.com/bensheldon/good_job/pull/106) ([bensheldon](https://github.com/bensheldon))
|
272
299
|
|
273
300
|
## [v1.2.3](https://github.com/bensheldon/good_job/tree/v1.2.3) (2020-08-27)
|
274
301
|
|
@@ -303,6 +330,7 @@
|
|
303
330
|
|
304
331
|
**Merged pull requests:**
|
305
332
|
|
333
|
+
- Re-organize Readme: frontload configuration, add Table of Contents [\#106](https://github.com/bensheldon/good_job/pull/106) ([bensheldon](https://github.com/bensheldon))
|
306
334
|
- Use more ActiveRecord in Lockable and not connection.execute [\#102](https://github.com/bensheldon/good_job/pull/102) ([bensheldon](https://github.com/bensheldon))
|
307
335
|
- 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))
|
308
336
|
- Fix Ruby 2.7 keyword arguments warning [\#98](https://github.com/bensheldon/good_job/pull/98) ([arku](https://github.com/arku))
|
@@ -435,6 +463,7 @@
|
|
435
463
|
|
436
464
|
- Add migration generator [\#56](https://github.com/bensheldon/good_job/pull/56) ([thedanbob](https://github.com/thedanbob))
|
437
465
|
- Fix migration script in readme [\#55](https://github.com/bensheldon/good_job/pull/55) ([thedanbob](https://github.com/thedanbob))
|
466
|
+
- Move where\(scheduled\_at: Time.current\) into dynamic part of GoodJob::Job::Performer [\#42](https://github.com/bensheldon/good_job/pull/42) ([bensheldon](https://github.com/bensheldon))
|
438
467
|
|
439
468
|
## [v1.0.1](https://github.com/bensheldon/good_job/tree/v1.0.1) (2020-07-22)
|
440
469
|
|
@@ -473,10 +502,6 @@
|
|
473
502
|
|
474
503
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v0.8.0...v0.8.1)
|
475
504
|
|
476
|
-
**Merged pull requests:**
|
477
|
-
|
478
|
-
- Move where\(scheduled\_at: Time.current\) into dynamic part of GoodJob::Job::Performer [\#42](https://github.com/bensheldon/good_job/pull/42) ([bensheldon](https://github.com/bensheldon))
|
479
|
-
|
480
505
|
## [v0.8.0](https://github.com/bensheldon/good_job/tree/v0.8.0) (2020-07-17)
|
481
506
|
|
482
507
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v0.7.0...v0.8.0)
|
data/README.md
CHANGED
@@ -149,12 +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
|
-
[--max-cache=COUNT]
|
156
|
-
[--
|
157
|
-
[--
|
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)
|
158
159
|
|
159
160
|
Executes queued jobs.
|
160
161
|
|
@@ -208,12 +209,15 @@ config.active_job.queue_adapter = :good_job
|
|
208
209
|
config.good_job.execution_mode = :async
|
209
210
|
config.good_job.max_threads = 5
|
210
211
|
config.good_job.poll_interval = 30 # seconds
|
212
|
+
config.good_job.shutdown_timeout = 25 # seconds
|
213
|
+
|
211
214
|
|
212
215
|
# ...or all at once.
|
213
216
|
config.good_job = {
|
214
217
|
execution_mode: :async,
|
215
218
|
max_threads: 5,
|
216
219
|
poll_interval: 30,
|
220
|
+
shutdown_timeout: 25,
|
217
221
|
}
|
218
222
|
```
|
219
223
|
|
@@ -227,6 +231,7 @@ Available configuration options are:
|
|
227
231
|
- `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`.
|
228
232
|
- `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
233
|
- `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`.
|
234
|
+
- `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`.
|
230
235
|
|
231
236
|
By default, GoodJob configures the following execution modes per environment:
|
232
237
|
|
data/lib/good_job.rb
CHANGED
@@ -78,15 +78,26 @@ module GoodJob
|
|
78
78
|
# See the {file:README.md#executing-jobs-async--in-process} for more explanation and examples.
|
79
79
|
# @param wait [Boolean] whether to wait for shutdown
|
80
80
|
# @return [void]
|
81
|
-
def self.shutdown(wait:
|
82
|
-
|
83
|
-
|
81
|
+
def self.shutdown(timeout: -1, wait: nil)
|
82
|
+
timeout = if wait.present?
|
83
|
+
ActiveSupport::Deprecation.warn(
|
84
|
+
"Using `GoodJob.shutdown` with `wait:` kwarg is deprecated; use `timeout:` kwarg instead e.g. GoodJob.shutdown(timeout: #{wait ? '-1' : 'nil'})"
|
85
|
+
)
|
86
|
+
wait ? -1 : nil
|
87
|
+
else
|
88
|
+
timeout
|
89
|
+
end
|
90
|
+
|
91
|
+
executables = Array(Notifier.instances) + Array(Poller.instances) + Array(Scheduler.instances)
|
92
|
+
_shutdown_all(executables, timeout: timeout)
|
84
93
|
end
|
85
94
|
|
86
95
|
# Tests whether jobs have stopped executing.
|
87
96
|
# @return [Boolean] whether background threads are shut down
|
88
97
|
def self.shutdown?
|
89
|
-
Notifier.instances.all?(&:shutdown?) &&
|
98
|
+
Notifier.instances.all?(&:shutdown?) &&
|
99
|
+
Poller.instances.all?(&:shutdown?) &&
|
100
|
+
Scheduler.instances.all?(&:shutdown?)
|
90
101
|
end
|
91
102
|
|
92
103
|
# Stops and restarts executing jobs.
|
@@ -95,9 +106,25 @@ module GoodJob
|
|
95
106
|
# For example, you should use +shutdown+ and +restart+ when using async execution mode with Puma.
|
96
107
|
# See the {file:README.md#executing-jobs-async--in-process} for more explanation and examples.
|
97
108
|
# @return [void]
|
98
|
-
def self.restart
|
99
|
-
Notifier.instances.
|
100
|
-
|
109
|
+
def self.restart(timeout: -1)
|
110
|
+
executables = Array(Notifier.instances) + Array(Poller.instances) + Array(Scheduler.instances)
|
111
|
+
_shutdown_all(executables, :restart, timeout: timeout)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Sends +#shutdown+ or +#restart+ to executable objects ({GoodJob::Notifier}, {GoodJob::Poller}, {GoodJob::Scheduler})
|
115
|
+
# @param executables [Array<(Notifier, Poller, Scheduler)>] Objects to shut down.
|
116
|
+
# @param method_name [:symbol] Method to call, e.g. +:shutdown+ or +:restart+.
|
117
|
+
# @param timeout [nil,Numeric]
|
118
|
+
# @return [void]
|
119
|
+
def self._shutdown_all(executables, method_name = :shutdown, timeout: -1)
|
120
|
+
if timeout.positive?
|
121
|
+
executables.each { |executable| executable.send(method_name, timeout: nil) }
|
122
|
+
|
123
|
+
stop_at = Time.current + timeout
|
124
|
+
executables.each { |executable| executable.send(method_name, timeout: [stop_at - Time.current, 0].max) }
|
125
|
+
else
|
126
|
+
executables.each { |executable| executable.send(method_name, timeout: timeout) }
|
127
|
+
end
|
101
128
|
end
|
102
129
|
|
103
130
|
ActiveSupport.run_load_hooks(:good_job, self)
|
data/lib/good_job/adapter.rb
CHANGED
@@ -38,7 +38,7 @@ module GoodJob
|
|
38
38
|
DEPRECATION
|
39
39
|
end
|
40
40
|
|
41
|
-
configuration = GoodJob::Configuration.new(
|
41
|
+
@configuration = GoodJob::Configuration.new(
|
42
42
|
{
|
43
43
|
execution_mode: execution_mode,
|
44
44
|
queues: queues,
|
@@ -47,13 +47,12 @@ module GoodJob
|
|
47
47
|
}
|
48
48
|
)
|
49
49
|
|
50
|
-
|
51
|
-
raise ArgumentError, "execution_mode: must be one of #{EXECUTION_MODES.join(', ')}." unless EXECUTION_MODES.include?(@execution_mode)
|
50
|
+
raise ArgumentError, "execution_mode: must be one of #{EXECUTION_MODES.join(', ')}." unless EXECUTION_MODES.include?(@configuration.execution_mode)
|
52
51
|
|
53
52
|
if execute_async? # rubocop:disable Style/GuardClause
|
54
53
|
@notifier = GoodJob::Notifier.new
|
55
|
-
@poller = GoodJob::Poller.new(poll_interval: configuration.poll_interval)
|
56
|
-
@scheduler = GoodJob::Scheduler.from_configuration(configuration, warm_cache_on_initialize: Rails.application.initialized?)
|
54
|
+
@poller = GoodJob::Poller.new(poll_interval: @configuration.poll_interval)
|
55
|
+
@scheduler = GoodJob::Scheduler.from_configuration(@configuration, warm_cache_on_initialize: Rails.application.initialized?)
|
57
56
|
@notifier.recipients << [@scheduler, :create_thread]
|
58
57
|
@poller.recipients << [@scheduler, :create_thread]
|
59
58
|
end
|
@@ -96,29 +95,48 @@ module GoodJob
|
|
96
95
|
good_job
|
97
96
|
end
|
98
97
|
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
98
|
+
# Shut down the thread pool executors.
|
99
|
+
# @param timeout [nil, Numeric] Seconds to wait for active threads.
|
100
|
+
#
|
101
|
+
# * +nil+, the scheduler will trigger a shutdown but not wait for it to complete.
|
102
|
+
# * +-1+, the scheduler will wait until the shutdown is complete.
|
103
|
+
# * +0+, the scheduler will immediately shutdown and stop any threads.
|
104
|
+
# * A positive number will wait that many seconds before stopping any remaining active threads.
|
105
|
+
# @param wait [Boolean] Deprecated. Use +timeout:+ instead.
|
102
106
|
# @return [void]
|
103
|
-
def shutdown(wait:
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
+
def shutdown(timeout: :default, wait: nil)
|
108
|
+
timeout = if wait.present?
|
109
|
+
ActiveSupport::Deprecation.warn(
|
110
|
+
"Using `GoodJob::Adapter.shutdown` with `wait:` kwarg is deprecated; use `timeout:` kwarg instead e.g. GoodJob::Adapter.shutdown(timeout: #{wait ? '-1' : 'nil'})"
|
111
|
+
)
|
112
|
+
wait ? -1 : nil
|
113
|
+
else
|
114
|
+
timeout
|
115
|
+
end
|
116
|
+
|
117
|
+
timeout = if timeout == :default
|
118
|
+
@configuration.shutdown_timeout
|
119
|
+
else
|
120
|
+
timeout
|
121
|
+
end
|
122
|
+
|
123
|
+
executables = [@notifier, @poller, @scheduler].compact
|
124
|
+
GoodJob._shutdown_all(executables, timeout: timeout)
|
107
125
|
end
|
108
126
|
|
109
127
|
# Whether in +:async+ execution mode.
|
110
128
|
def execute_async?
|
111
|
-
@execution_mode == :async
|
129
|
+
@configuration.execution_mode == :async
|
112
130
|
end
|
113
131
|
|
114
132
|
# Whether in +:external+ execution mode.
|
115
133
|
def execute_externally?
|
116
|
-
@execution_mode == :external
|
134
|
+
@configuration.execution_mode == :external
|
117
135
|
end
|
118
136
|
|
119
137
|
# Whether in +:inline+ execution mode.
|
120
138
|
def execute_inline?
|
121
|
-
@execution_mode == :inline
|
139
|
+
@configuration.execution_mode == :inline
|
122
140
|
end
|
123
141
|
end
|
124
142
|
end
|
data/lib/good_job/cli.rb
CHANGED
@@ -53,6 +53,10 @@ module GoodJob
|
|
53
53
|
type: :numeric,
|
54
54
|
banner: 'COUNT',
|
55
55
|
desc: "Maximum number of scheduled jobs to cache in memory (env var: GOOD_JOB_MAX_CACHE, default: 10000)"
|
56
|
+
method_option :shutdown_timeout,
|
57
|
+
type: :numeric,
|
58
|
+
banner: 'SECONDS',
|
59
|
+
desc: "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))"
|
56
60
|
method_option :daemonize,
|
57
61
|
type: :boolean,
|
58
62
|
desc: "Run as a background daemon (default: false)"
|
@@ -81,9 +85,8 @@ module GoodJob
|
|
81
85
|
break if @stop_good_job_executable || scheduler.shutdown? || notifier.shutdown?
|
82
86
|
end
|
83
87
|
|
84
|
-
notifier
|
85
|
-
|
86
|
-
scheduler.shutdown
|
88
|
+
executors = [notifier, poller, scheduler]
|
89
|
+
GoodJob._shutdown_all(executors, timeout: configuration.shutdown_timeout)
|
87
90
|
end
|
88
91
|
|
89
92
|
default_task :start
|
@@ -13,6 +13,8 @@ module GoodJob
|
|
13
13
|
DEFAULT_MAX_CACHE = 10000
|
14
14
|
# Default number of seconds to preserve jobs for {CLI#cleanup_preserved_jobs}
|
15
15
|
DEFAULT_CLEANUP_PRESERVED_JOBS_BEFORE_SECONDS_AGO = 24 * 60 * 60
|
16
|
+
# Default to always wait for jobs to finish for {#shutdown}
|
17
|
+
DEFAULT_SHUTDOWN_TIMEOUT = -1
|
16
18
|
|
17
19
|
# The options that were explicitly set when initializing +Configuration+.
|
18
20
|
# @return [Hash]
|
@@ -77,10 +79,10 @@ module GoodJob
|
|
77
79
|
def max_threads
|
78
80
|
(
|
79
81
|
options[:max_threads] ||
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
82
|
+
rails_config[:max_threads] ||
|
83
|
+
env['GOOD_JOB_MAX_THREADS'] ||
|
84
|
+
env['RAILS_MAX_THREADS'] ||
|
85
|
+
DEFAULT_MAX_THREADS
|
84
86
|
).to_i
|
85
87
|
end
|
86
88
|
|
@@ -103,9 +105,9 @@ module GoodJob
|
|
103
105
|
def poll_interval
|
104
106
|
(
|
105
107
|
options[:poll_interval] ||
|
106
|
-
|
107
|
-
|
108
|
-
|
108
|
+
rails_config[:poll_interval] ||
|
109
|
+
env['GOOD_JOB_POLL_INTERVAL'] ||
|
110
|
+
DEFAULT_POLL_INTERVAL
|
109
111
|
).to_i
|
110
112
|
end
|
111
113
|
|
@@ -122,15 +124,27 @@ module GoodJob
|
|
122
124
|
).to_i
|
123
125
|
end
|
124
126
|
|
127
|
+
# The number of seconds to wait for jobs to finish when shutting down
|
128
|
+
# before stopping the thread. +-1+ is forever.
|
129
|
+
# @return [Numeric]
|
130
|
+
def shutdown_timeout
|
131
|
+
(
|
132
|
+
options[:shutdown_timeout] ||
|
133
|
+
rails_config[:shutdown_timeout] ||
|
134
|
+
env['GOOD_JOB_SHUTDOWN_TIMEOUT'] ||
|
135
|
+
DEFAULT_SHUTDOWN_TIMEOUT
|
136
|
+
).to_f
|
137
|
+
end
|
138
|
+
|
125
139
|
# Number of seconds to preserve jobs when using the +good_job cleanup_preserved_jobs+ CLI command.
|
126
140
|
# This configuration is only used when {GoodJob.preserve_job_records} is +true+.
|
127
141
|
# @return [Integer]
|
128
142
|
def cleanup_preserved_jobs_before_seconds_ago
|
129
143
|
(
|
130
144
|
options[:before_seconds_ago] ||
|
131
|
-
|
132
|
-
|
133
|
-
|
145
|
+
rails_config[:cleanup_preserved_jobs_before_seconds_ago] ||
|
146
|
+
env['GOOD_JOB_CLEANUP_PRESERVED_JOBS_BEFORE_SECONDS_AGO'] ||
|
147
|
+
DEFAULT_CLEANUP_PRESERVED_JOBS_BEFORE_SECONDS_AGO
|
134
148
|
).to_i
|
135
149
|
end
|
136
150
|
|
data/lib/good_job/job.rb
CHANGED
@@ -51,8 +51,9 @@ module GoodJob
|
|
51
51
|
end
|
52
52
|
|
53
53
|
# The Returns timestamps of when next tasks may be available.
|
54
|
-
# @param
|
55
|
-
# @param
|
54
|
+
# @param after [DateTime, Time, nil] future jobs scheduled after this time
|
55
|
+
# @param limit [Integer] number of future timestamps to return
|
56
|
+
# @param now_limit [Integer] number of past timestamps to return
|
56
57
|
# @return [Array<(Time, Timestamp)>, nil]
|
57
58
|
def next_at(after: nil, limit: nil, now_limit: nil)
|
58
59
|
job_query.next_scheduled_at(after: after, limit: limit, now_limit: now_limit)
|
@@ -1,16 +1,16 @@
|
|
1
1
|
module GoodJob
|
2
2
|
# Delegates the interface of a single {Scheduler} to multiple Schedulers.
|
3
3
|
class MultiScheduler
|
4
|
-
# @return [
|
4
|
+
# @return [Array<Scheduler>] List of the scheduler delegates
|
5
5
|
attr_reader :schedulers
|
6
6
|
|
7
7
|
def initialize(schedulers)
|
8
8
|
@schedulers = schedulers
|
9
9
|
end
|
10
10
|
|
11
|
-
# Delegates to {Scheduler#
|
12
|
-
def
|
13
|
-
schedulers.
|
11
|
+
# Delegates to {Scheduler#running?}.
|
12
|
+
def running?
|
13
|
+
schedulers.all?(&:running?)
|
14
14
|
end
|
15
15
|
|
16
16
|
# Delegates to {Scheduler#shutdown?}.
|
@@ -18,9 +18,14 @@ module GoodJob
|
|
18
18
|
schedulers.all?(&:shutdown?)
|
19
19
|
end
|
20
20
|
|
21
|
+
# Delegates to {Scheduler#shutdown}.
|
22
|
+
def shutdown(timeout: -1)
|
23
|
+
GoodJob._shutdown_all(schedulers, timeout: timeout)
|
24
|
+
end
|
25
|
+
|
21
26
|
# Delegates to {Scheduler#restart}.
|
22
|
-
def restart(
|
23
|
-
schedulers
|
27
|
+
def restart(timeout: -1)
|
28
|
+
GoodJob._shutdown_all(schedulers, :restart, timeout: timeout)
|
24
29
|
end
|
25
30
|
|
26
31
|
# Delegates to {Scheduler#create_thread}.
|
data/lib/good_job/notifier.rb
CHANGED
@@ -15,7 +15,7 @@ module GoodJob # :nodoc:
|
|
15
15
|
# Default Postgres channel for LISTEN/NOTIFY
|
16
16
|
CHANNEL = 'good_job'.freeze
|
17
17
|
# Defaults for instance of Concurrent::ThreadPoolExecutor
|
18
|
-
|
18
|
+
EXECUTOR_OPTIONS = {
|
19
19
|
name: name,
|
20
20
|
min_threads: 0,
|
21
21
|
max_threads: 1,
|
@@ -30,7 +30,7 @@ module GoodJob # :nodoc:
|
|
30
30
|
# @!attribute [r] instances
|
31
31
|
# @!scope class
|
32
32
|
# List of all instantiated Notifiers in the current process.
|
33
|
-
# @return [
|
33
|
+
# @return [Array<GoodJob:Adapter>]
|
34
34
|
cattr_reader :instances, default: [], instance_reader: false
|
35
35
|
|
36
36
|
# Send a message via Postgres NOTIFY
|
@@ -53,7 +53,7 @@ module GoodJob # :nodoc:
|
|
53
53
|
|
54
54
|
self.class.instances << self
|
55
55
|
|
56
|
-
|
56
|
+
create_executor
|
57
57
|
listen
|
58
58
|
end
|
59
59
|
|
@@ -63,34 +63,43 @@ module GoodJob # :nodoc:
|
|
63
63
|
@listening.true?
|
64
64
|
end
|
65
65
|
|
66
|
-
#
|
67
|
-
#
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
listen
|
74
|
-
end
|
66
|
+
# Tests whether the notifier is running.
|
67
|
+
# @return [true, false, nil]
|
68
|
+
delegate :running?, to: :executor, allow_nil: true
|
69
|
+
|
70
|
+
# Tests whether the scheduler is shutdown.
|
71
|
+
# @return [true, false, nil]
|
72
|
+
delegate :shutdown?, to: :executor, allow_nil: true
|
75
73
|
|
76
74
|
# Shut down the notifier.
|
77
75
|
# This stops the background LISTENing thread.
|
78
|
-
# If +wait+ is +true+, the notifier will wait for background thread to shutdown.
|
79
|
-
# If +wait+ is +false+, this method will return immediately even though threads may still be running.
|
80
76
|
# Use {#shutdown?} to determine whether threads have stopped.
|
81
|
-
# @param
|
77
|
+
# @param timeout [nil, Numeric] Seconds to wait for active threads.
|
78
|
+
#
|
79
|
+
# * +nil+, the scheduler will trigger a shutdown but not wait for it to complete.
|
80
|
+
# * +-1+, the scheduler will wait until the shutdown is complete.
|
81
|
+
# * +0+, the scheduler will immediately shutdown and stop any threads.
|
82
|
+
# * A positive number will wait that many seconds before stopping any remaining active threads.
|
82
83
|
# @return [void]
|
83
|
-
def shutdown(
|
84
|
-
return
|
84
|
+
def shutdown(timeout: -1)
|
85
|
+
return if executor.nil? || executor.shutdown?
|
85
86
|
|
86
|
-
|
87
|
-
|
87
|
+
executor.shutdown if executor.running?
|
88
|
+
|
89
|
+
if executor.shuttingdown? && timeout # rubocop:disable Style/GuardClause
|
90
|
+
executor_wait = timeout.negative? ? nil : timeout
|
91
|
+
executor.kill unless executor.wait_for_termination(executor_wait)
|
92
|
+
end
|
88
93
|
end
|
89
94
|
|
90
|
-
#
|
91
|
-
#
|
92
|
-
|
93
|
-
|
95
|
+
# Restart the notifier.
|
96
|
+
# When shutdown, start; or shutdown and start.
|
97
|
+
# @param timeout [nil, Numeric] Seconds to wait; shares same values as {#shutdown}.
|
98
|
+
# @return [void]
|
99
|
+
def restart(timeout: -1)
|
100
|
+
shutdown(timeout: timeout) if running?
|
101
|
+
create_executor
|
102
|
+
listen
|
94
103
|
end
|
95
104
|
|
96
105
|
# Invoked on completion of ThreadPoolExecutor task
|
@@ -109,36 +118,36 @@ module GoodJob # :nodoc:
|
|
109
118
|
|
110
119
|
private
|
111
120
|
|
112
|
-
|
113
|
-
|
121
|
+
attr_reader :executor
|
122
|
+
|
123
|
+
def create_executor
|
124
|
+
@executor = Concurrent::ThreadPoolExecutor.new(EXECUTOR_OPTIONS)
|
114
125
|
end
|
115
126
|
|
116
127
|
def listen
|
117
|
-
future = Concurrent::Future.new(args: [@recipients,
|
128
|
+
future = Concurrent::Future.new(args: [@recipients, executor, @listening], executor: @executor) do |thr_recipients, thr_executor, thr_listening|
|
118
129
|
with_listen_connection do |conn|
|
119
130
|
ActiveSupport::Notifications.instrument("notifier_listen.good_job") do
|
120
131
|
conn.async_exec("LISTEN #{CHANNEL}").clear
|
121
132
|
end
|
122
133
|
|
123
134
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
124
|
-
|
125
|
-
|
135
|
+
thr_listening.make_true
|
136
|
+
while thr_executor.running?
|
126
137
|
conn.wait_for_notify(WAIT_INTERVAL) do |channel, _pid, payload|
|
127
|
-
listening.make_false
|
128
138
|
next unless channel == CHANNEL
|
129
139
|
|
130
140
|
ActiveSupport::Notifications.instrument("notifier_notified.good_job", { payload: payload })
|
131
141
|
parsed_payload = JSON.parse(payload, symbolize_names: true)
|
132
|
-
|
142
|
+
thr_recipients.each do |recipient|
|
133
143
|
target, method_name = recipient.is_a?(Array) ? recipient : [recipient, :call]
|
134
144
|
target.send(method_name, parsed_payload)
|
135
145
|
end
|
136
146
|
end
|
137
|
-
listening.make_false
|
138
147
|
end
|
139
148
|
end
|
140
149
|
ensure
|
141
|
-
|
150
|
+
thr_listening.make_false
|
142
151
|
ActiveSupport::Notifications.instrument("notifier_unlisten.good_job") do
|
143
152
|
conn.async_exec("UNLISTEN *").clear
|
144
153
|
end
|
data/lib/good_job/poller.rb
CHANGED
@@ -16,7 +16,7 @@ module GoodJob # :nodoc:
|
|
16
16
|
# @!attribute [r] instances
|
17
17
|
# @!scope class
|
18
18
|
# List of all instantiated Pollers in the current process.
|
19
|
-
# @return [
|
19
|
+
# @return [Array<GoodJob:Poller>]
|
20
20
|
cattr_reader :instances, default: [], instance_reader: false
|
21
21
|
|
22
22
|
# Creates GoodJob::Poller from a GoodJob::Configuration instance.
|
@@ -40,35 +40,44 @@ module GoodJob # :nodoc:
|
|
40
40
|
|
41
41
|
self.class.instances << self
|
42
42
|
|
43
|
-
|
43
|
+
create_timer
|
44
44
|
end
|
45
45
|
|
46
|
-
#
|
47
|
-
#
|
48
|
-
|
46
|
+
# Tests whether the timer is running.
|
47
|
+
# @return [true, false, nil]
|
48
|
+
delegate :running?, to: :timer, allow_nil: true
|
49
|
+
|
50
|
+
# Tests whether the timer is shutdown.
|
51
|
+
# @return [true, false, nil]
|
52
|
+
delegate :shutdown?, to: :timer, allow_nil: true
|
53
|
+
|
54
|
+
# Shut down the notifier.
|
49
55
|
# Use {#shutdown?} to determine whether threads have stopped.
|
50
|
-
# @param
|
56
|
+
# @param timeout [nil, Numeric] Seconds to wait for active threads.
|
57
|
+
#
|
58
|
+
# * +nil+, the scheduler will trigger a shutdown but not wait for it to complete.
|
59
|
+
# * +-1+, the scheduler will wait until the shutdown is complete.
|
60
|
+
# * +0+, the scheduler will immediately shutdown and stop any threads.
|
61
|
+
# * A positive number will wait that many seconds before stopping any remaining active threads.
|
51
62
|
# @return [void]
|
52
|
-
def shutdown(
|
53
|
-
return
|
63
|
+
def shutdown(timeout: -1)
|
64
|
+
return if timer.nil? || timer.shutdown?
|
54
65
|
|
55
|
-
|
56
|
-
@timer.wait_for_termination if wait
|
57
|
-
end
|
66
|
+
timer.shutdown if timer.running?
|
58
67
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
68
|
+
if timer.shuttingdown? && timeout # rubocop:disable Style/GuardClause
|
69
|
+
timer_wait = timeout.negative? ? nil : timeout
|
70
|
+
timer.kill unless timer.wait_for_termination(timer_wait)
|
71
|
+
end
|
63
72
|
end
|
64
73
|
|
65
74
|
# Restart the poller.
|
66
75
|
# When shutdown, start; or shutdown and start.
|
67
|
-
# @param
|
76
|
+
# @param timeout [nil, Numeric] Seconds to wait; shares same values as {#shutdown}.
|
68
77
|
# @return [void]
|
69
|
-
def restart(
|
70
|
-
shutdown(
|
71
|
-
|
78
|
+
def restart(timeout: -1)
|
79
|
+
shutdown(timeout: timeout) if running?
|
80
|
+
create_timer
|
72
81
|
end
|
73
82
|
|
74
83
|
# Invoked on completion of TimerTask task.
|
@@ -81,7 +90,9 @@ module GoodJob # :nodoc:
|
|
81
90
|
|
82
91
|
private
|
83
92
|
|
84
|
-
|
93
|
+
attr_reader :timer
|
94
|
+
|
95
|
+
def create_timer
|
85
96
|
return if @timer_options[:execution_interval] <= 0
|
86
97
|
|
87
98
|
@timer = Concurrent::TimerTask.new(@timer_options) do
|
data/lib/good_job/scheduler.rb
CHANGED
@@ -16,8 +16,8 @@ module GoodJob # :nodoc:
|
|
16
16
|
#
|
17
17
|
class Scheduler
|
18
18
|
# Defaults for instance of Concurrent::ThreadPoolExecutor
|
19
|
-
# The thread pool is where work is performed.
|
20
|
-
|
19
|
+
# The thread pool executor is where work is performed.
|
20
|
+
DEFAULT_EXECUTOR_OPTIONS = {
|
21
21
|
name: name,
|
22
22
|
min_threads: 0,
|
23
23
|
max_threads: Configuration::DEFAULT_MAX_THREADS,
|
@@ -30,7 +30,7 @@ module GoodJob # :nodoc:
|
|
30
30
|
# @!attribute [r] instances
|
31
31
|
# @!scope class
|
32
32
|
# List of all instantiated Schedulers in the current process.
|
33
|
-
# @return [
|
33
|
+
# @return [Array<GoodJob:Scheduler>]
|
34
34
|
cattr_reader :instances, default: [], instance_reader: false
|
35
35
|
|
36
36
|
# Creates GoodJob::Scheduler(s) and Performers from a GoodJob::Configuration instance.
|
@@ -70,66 +70,76 @@ module GoodJob # :nodoc:
|
|
70
70
|
@performer = performer
|
71
71
|
|
72
72
|
@max_cache = max_cache || 0
|
73
|
-
@
|
73
|
+
@executor_options = DEFAULT_EXECUTOR_OPTIONS.dup
|
74
74
|
if max_threads.present?
|
75
|
-
@
|
76
|
-
@
|
75
|
+
@executor_options[:max_threads] = max_threads
|
76
|
+
@executor_options[:max_queue] = max_threads
|
77
77
|
end
|
78
|
-
@
|
78
|
+
@executor_options[:name] = "GoodJob::Scheduler(queues=#{@performer.name} max_threads=#{@executor_options[:max_threads]})"
|
79
79
|
|
80
|
-
|
80
|
+
create_executor
|
81
81
|
warm_cache if warm_cache_on_initialize
|
82
82
|
end
|
83
83
|
|
84
|
+
# Tests whether the scheduler is running.
|
85
|
+
# @return [true, false, nil]
|
86
|
+
delegate :running?, to: :executor, allow_nil: true
|
87
|
+
|
88
|
+
# Tests whether the scheduler is shutdown.
|
89
|
+
# @return [true, false, nil]
|
90
|
+
delegate :shutdown?, to: :executor, allow_nil: true
|
91
|
+
|
84
92
|
# Shut down the scheduler.
|
85
|
-
# This stops all threads in the pool.
|
86
|
-
# If +wait+ is +true+, the scheduler will wait for any active tasks to finish.
|
87
|
-
# If +wait+ is +false+, this method will return immediately even though threads may still be running.
|
93
|
+
# This stops all threads in the thread pool.
|
88
94
|
# Use {#shutdown?} to determine whether threads have stopped.
|
89
|
-
# @param
|
95
|
+
# @param timeout [nil, Numeric] Seconds to wait for actively executing jobs to finish
|
96
|
+
#
|
97
|
+
# * +nil+, the scheduler will trigger a shutdown but not wait for it to complete.
|
98
|
+
# * +-1+, the scheduler will wait until the shutdown is complete.
|
99
|
+
# * +0+, the scheduler will immediately shutdown and stop any active tasks.
|
100
|
+
# * A positive number will wait that many seconds before stopping any remaining active tasks.
|
90
101
|
# @return [void]
|
91
|
-
def shutdown(
|
92
|
-
return
|
93
|
-
|
94
|
-
instrument("scheduler_shutdown_start", {
|
95
|
-
instrument("scheduler_shutdown", {
|
96
|
-
|
102
|
+
def shutdown(timeout: -1)
|
103
|
+
return if executor.nil? || executor.shutdown?
|
104
|
+
|
105
|
+
instrument("scheduler_shutdown_start", { timeout: timeout })
|
106
|
+
instrument("scheduler_shutdown", { timeout: timeout }) do
|
107
|
+
if executor.running?
|
108
|
+
@timer_set.shutdown
|
109
|
+
executor.shutdown
|
110
|
+
end
|
97
111
|
|
98
|
-
|
99
|
-
|
100
|
-
|
112
|
+
if executor.shuttingdown? && timeout
|
113
|
+
executor_wait = timeout.negative? ? nil : timeout
|
114
|
+
executor.kill unless executor.wait_for_termination(executor_wait)
|
115
|
+
end
|
101
116
|
end
|
102
117
|
end
|
103
118
|
|
104
|
-
# Tests whether the scheduler is shutdown.
|
105
|
-
# @return [true, false, nil]
|
106
|
-
def shutdown?
|
107
|
-
!@pool&.running?
|
108
|
-
end
|
109
|
-
|
110
119
|
# Restart the Scheduler.
|
111
120
|
# When shutdown, start; or shutdown and start.
|
112
|
-
# @param
|
121
|
+
# @param timeout [nil, Numeric] Seconds to wait for actively executing jobs to finish; shares same values as {#shutdown}.
|
113
122
|
# @return [void]
|
114
|
-
def restart(
|
123
|
+
def restart(timeout: -1)
|
115
124
|
instrument("scheduler_restart_pools") do
|
116
|
-
shutdown(
|
117
|
-
|
125
|
+
shutdown(timeout: timeout) if running?
|
126
|
+
create_executor
|
118
127
|
warm_cache
|
119
128
|
end
|
120
129
|
end
|
121
130
|
|
122
131
|
# Wakes a thread to allow the performer to execute a task.
|
123
|
-
# @param state [nil, Object] Contextual information for the performer. See {
|
132
|
+
# @param state [nil, Object] Contextual information for the performer. See {JobPerformer#next?}.
|
124
133
|
# @return [nil, Boolean] Whether work was started.
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
134
|
+
#
|
135
|
+
# * +nil+ if the scheduler is unable to take new work, for example if the thread pool is shut down or at capacity.
|
136
|
+
# * +true+ if the performer started executing work.
|
137
|
+
# * +false+ if the performer decides not to attempt to execute a task based on the +state+ that is passed to it.
|
128
138
|
def create_thread(state = nil)
|
129
|
-
return nil unless
|
139
|
+
return nil unless executor.running?
|
130
140
|
|
131
141
|
if state
|
132
|
-
return false unless
|
142
|
+
return false unless performer.next?(state)
|
133
143
|
|
134
144
|
if state[:scheduled_at]
|
135
145
|
scheduled_at = if state[:scheduled_at].is_a? String
|
@@ -144,18 +154,12 @@ module GoodJob # :nodoc:
|
|
144
154
|
delay ||= 0
|
145
155
|
run_now = delay <= 0.01
|
146
156
|
if run_now
|
147
|
-
return nil unless
|
157
|
+
return nil unless executor.ready_worker_count.positive?
|
148
158
|
elsif @max_cache.positive?
|
149
159
|
return nil unless remaining_cache_count.positive?
|
150
160
|
end
|
151
161
|
|
152
|
-
|
153
|
-
output = nil
|
154
|
-
Rails.application.executor.wrap { output = performer.next }
|
155
|
-
output
|
156
|
-
end
|
157
|
-
future.add_observer(self, :task_observer)
|
158
|
-
future.execute
|
162
|
+
create_task(delay)
|
159
163
|
|
160
164
|
run_now ? true : nil
|
161
165
|
end
|
@@ -169,44 +173,46 @@ module GoodJob # :nodoc:
|
|
169
173
|
create_task if output
|
170
174
|
end
|
171
175
|
|
176
|
+
# Information about the Scheduler
|
177
|
+
# @return [Hash]
|
178
|
+
def stats
|
179
|
+
{
|
180
|
+
name: performer.name,
|
181
|
+
max_threads: @executor_options[:max_threads],
|
182
|
+
active_threads: @executor_options[:max_threads] - executor.ready_worker_count,
|
183
|
+
available_threads: executor.ready_worker_count,
|
184
|
+
max_cache: @max_cache,
|
185
|
+
active_cache: cache_count,
|
186
|
+
available_cache: remaining_cache_count,
|
187
|
+
}
|
188
|
+
end
|
189
|
+
|
172
190
|
def warm_cache
|
173
191
|
return if @max_cache.zero?
|
174
192
|
|
175
|
-
|
193
|
+
performer.next_at(
|
176
194
|
limit: @max_cache,
|
177
|
-
now_limit: @
|
195
|
+
now_limit: @executor_options[:max_threads]
|
178
196
|
).each do |scheduled_at|
|
179
197
|
create_thread({ scheduled_at: scheduled_at })
|
180
198
|
end
|
181
199
|
end
|
182
200
|
|
183
|
-
def stats
|
184
|
-
{
|
185
|
-
name: @performer.name,
|
186
|
-
max_threads: @pool_options[:max_threads],
|
187
|
-
active_threads: @pool_options[:max_threads] - @pool.ready_worker_count,
|
188
|
-
available_threads: @pool.ready_worker_count,
|
189
|
-
max_cache: @max_cache,
|
190
|
-
active_cache: cache_count,
|
191
|
-
available_cache: remaining_cache_count,
|
192
|
-
}
|
193
|
-
end
|
194
|
-
|
195
201
|
private
|
196
202
|
|
197
|
-
attr_reader :timer_set
|
203
|
+
attr_reader :performer, :executor, :timer_set
|
198
204
|
|
199
|
-
def
|
200
|
-
instrument("scheduler_create_pool", { performer_name:
|
205
|
+
def create_executor
|
206
|
+
instrument("scheduler_create_pool", { performer_name: performer.name, max_threads: @executor_options[:max_threads] }) do
|
201
207
|
@timer_set = Concurrent::TimerSet.new
|
202
|
-
@
|
208
|
+
@executor = ThreadPoolExecutor.new(@executor_options)
|
203
209
|
end
|
204
210
|
end
|
205
211
|
|
206
212
|
def create_task(delay = 0)
|
207
|
-
future = Concurrent::ScheduledTask.new(delay, args: [
|
213
|
+
future = Concurrent::ScheduledTask.new(delay, args: [performer], executor: executor, timer_set: timer_set) do |thr_performer|
|
208
214
|
output = nil
|
209
|
-
Rails.application.executor.wrap { output =
|
215
|
+
Rails.application.executor.wrap { output = thr_performer.next }
|
210
216
|
output
|
211
217
|
end
|
212
218
|
future.add_observer(self, :task_observer)
|
data/lib/good_job/version.rb
CHANGED
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: 1.
|
4
|
+
version: 1.8.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: 2021-
|
11
|
+
date: 2021-03-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -400,7 +400,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
400
400
|
- !ruby/object:Gem::Version
|
401
401
|
version: '0'
|
402
402
|
requirements: []
|
403
|
-
rubygems_version: 3.
|
403
|
+
rubygems_version: 3.1.4
|
404
404
|
signing_key:
|
405
405
|
specification_version: 4
|
406
406
|
summary: A multithreaded, Postgres-based ActiveJob backend for Ruby on Rails
|