good_job 1.9.3 → 1.9.4
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 +28 -1
- data/engine/app/controllers/good_job/dashboards_controller.rb +7 -5
- data/engine/app/views/shared/_chart.erb +3 -2
- data/lib/good_job.rb +12 -8
- data/lib/good_job/adapter.rb +14 -11
- data/lib/good_job/configuration.rb +3 -3
- data/lib/good_job/current_execution.rb +0 -1
- data/lib/good_job/daemon.rb +6 -0
- data/lib/good_job/job.rb +15 -1
- data/lib/good_job/job_performer.rb +2 -2
- data/lib/good_job/lockable.rb +2 -5
- data/lib/good_job/log_subscriber.rb +15 -14
- data/lib/good_job/multi_scheduler.rb +9 -0
- data/lib/good_job/notifier.rb +4 -2
- data/lib/good_job/poller.rb +9 -4
- data/lib/good_job/scheduler.rb +12 -6
- data/lib/good_job/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '039fb246e970dd21bfa88b72a50fd96038c00bd4dd0c323966936a9899ade684'
|
4
|
+
data.tar.gz: bb19f26989f503ce572759c7726b07ee56208b0defc793de6e0ca07c500cb869
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78516e648a709192486d728061d19850f108daa6863ec714b51ee1eb0e03c1ca7a6294d4736e70e8d657d34abfd8105168a94b26a2fe7ec33df0db4e04587574
|
7
|
+
data.tar.gz: 416b0b8fb14e082abefffd7d5a4ee7eea53725eeba4dd0d7786e6c8caaa833cb318a5205863ae6aa6e3d475e9abfd3aff687ccde2bc93b4b435764f614c8251a
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,32 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v1.9.4](https://github.com/bensheldon/good_job/tree/v1.9.4) (2021-05-18)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.9.3...v1.9.4)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Add "running" jobs state to Dashboard [\#253](https://github.com/bensheldon/good_job/pull/253) ([morgoth](https://github.com/morgoth))
|
10
|
+
|
11
|
+
**Fixed bugs:**
|
12
|
+
|
13
|
+
- Unify displaying timestamps [\#252](https://github.com/bensheldon/good_job/pull/252) ([morgoth](https://github.com/morgoth))
|
14
|
+
- Fix dashboard jobs endless pagination with timezone handling [\#251](https://github.com/bensheldon/good_job/pull/251) ([morgoth](https://github.com/morgoth))
|
15
|
+
|
16
|
+
**Closed issues:**
|
17
|
+
|
18
|
+
- exception\_executions not counted correctly? [\#215](https://github.com/bensheldon/good_job/issues/215)
|
19
|
+
- Document issues with PgBouncer and session-level Advisory Locks [\#52](https://github.com/bensheldon/good_job/issues/52)
|
20
|
+
|
21
|
+
**Merged pull requests:**
|
22
|
+
|
23
|
+
- Add handy scope for filtering by job class [\#259](https://github.com/bensheldon/good_job/pull/259) ([morgoth](https://github.com/morgoth))
|
24
|
+
- Nest exception stub within job class and cleanup let! precedence to fix flakey JRuby tests [\#254](https://github.com/bensheldon/good_job/pull/254) ([bensheldon](https://github.com/bensheldon))
|
25
|
+
- Move good\_job\_spec.rb to proper location in lib directory [\#250](https://github.com/bensheldon/good_job/pull/250) ([bensheldon](https://github.com/bensheldon))
|
26
|
+
- Refactor deprecated wait parameter and assorted improvements [\#249](https://github.com/bensheldon/good_job/pull/249) ([bensheldon](https://github.com/bensheldon))
|
27
|
+
- Update development dependencies \(Rails v6.1.3.2\) [\#248](https://github.com/bensheldon/good_job/pull/248) ([bensheldon](https://github.com/bensheldon))
|
28
|
+
- Update YARD documentation param types and return values [\#239](https://github.com/bensheldon/good_job/pull/239) ([bensheldon](https://github.com/bensheldon))
|
29
|
+
|
3
30
|
## [v1.9.3](https://github.com/bensheldon/good_job/tree/v1.9.3) (2021-05-10)
|
4
31
|
|
5
32
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v1.9.2...v1.9.3)
|
@@ -10,7 +37,7 @@
|
|
10
37
|
|
11
38
|
**Closed issues:**
|
12
39
|
|
13
|
-
- Not processing unfinished jobs across server restarts using async\_server mode
|
40
|
+
- Not processing unfinished jobs across server restarts using async\_server mode on Iodine server [\#244](https://github.com/bensheldon/good_job/issues/244)
|
14
41
|
- No connection pool for 'ActiveRecord::Base' found [\#236](https://github.com/bensheldon/good_job/issues/236)
|
15
42
|
|
16
43
|
## [v1.9.2](https://github.com/bensheldon/good_job/tree/v1.9.2) (2021-05-10)
|
@@ -12,17 +12,18 @@ module GoodJob
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def jobs
|
15
|
-
|
15
|
+
after_scheduled_at = params[:after_scheduled_at].present? ? Time.zone.parse(params[:after_scheduled_at]) : nil
|
16
|
+
sql = GoodJob::Job.display_all(after_scheduled_at: after_scheduled_at, after_id: params[:after_id])
|
16
17
|
.limit(params.fetch(:limit, 10))
|
17
|
-
|
18
|
-
sql = sql.where("serialized_params->>'job_class' = ?", params[:job_class])
|
19
|
-
end
|
18
|
+
sql = sql.with_job_class(params[:job_class]) if params[:job_class]
|
20
19
|
if params[:state]
|
21
20
|
case params[:state]
|
22
21
|
when 'finished'
|
23
22
|
sql = sql.finished
|
24
23
|
when 'unfinished'
|
25
24
|
sql = sql.unfinished
|
25
|
+
when 'running'
|
26
|
+
sql = sql.running
|
26
27
|
when 'errors'
|
27
28
|
sql = sql.where.not(error: nil)
|
28
29
|
end
|
@@ -34,6 +35,7 @@ module GoodJob
|
|
34
35
|
{
|
35
36
|
'finished' => GoodJob::Job.finished.count,
|
36
37
|
'unfinished' => GoodJob::Job.unfinished.count,
|
38
|
+
'running' => GoodJob::Job.running.count,
|
37
39
|
'errors' => GoodJob::Job.where.not(error: nil).count,
|
38
40
|
}
|
39
41
|
end
|
@@ -79,7 +81,7 @@ module GoodJob
|
|
79
81
|
queue_names = job_data.map { |d| d['queue_name'] }.uniq
|
80
82
|
labels = []
|
81
83
|
queues_data = job_data.to_a.group_by { |d| d['timestamp'] }.each_with_object({}) do |(timestamp, values), hash|
|
82
|
-
labels << timestamp
|
84
|
+
labels << timestamp.in_time_zone.to_s
|
83
85
|
queue_names.each do |queue_name|
|
84
86
|
(hash[queue_name] ||= []) << values.find { |d| d['queue_name'] == queue_name }&.[]('count')
|
85
87
|
end
|
@@ -6,11 +6,12 @@
|
|
6
6
|
fullWidth: true,
|
7
7
|
chartPadding: {
|
8
8
|
right: 40,
|
9
|
-
top: 20
|
9
|
+
top: 20,
|
10
|
+
bottom: 20
|
10
11
|
},
|
11
12
|
axisX: {
|
12
13
|
labelInterpolationFnc: function(value, index) {
|
13
|
-
return index % 3
|
14
|
+
return index % 3 === 0 ? value : null;
|
14
15
|
}
|
15
16
|
},
|
16
17
|
axisY: {
|
data/lib/good_job.rb
CHANGED
@@ -30,7 +30,7 @@ module GoodJob
|
|
30
30
|
# @!scope class
|
31
31
|
# The logger used by GoodJob (default: +Rails.logger+).
|
32
32
|
# Use this to redirect logs to a special location or file.
|
33
|
-
# @return [Logger]
|
33
|
+
# @return [Logger, nil]
|
34
34
|
# @example Output GoodJob logs to a file:
|
35
35
|
# GoodJob.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new("log/my_logs.log"))
|
36
36
|
mattr_accessor :logger, default: ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new($stdout))
|
@@ -42,7 +42,7 @@ module GoodJob
|
|
42
42
|
# If you want to preserve jobs for latter inspection, set this to +true+.
|
43
43
|
# If you want to preserve only jobs that finished with error for latter inspection, set this to +:on_unhandled_error+.
|
44
44
|
# If +true+, you will need to clean out jobs using the +good_job cleanup_preserved_jobs+ CLI command.
|
45
|
-
# @return [Boolean]
|
45
|
+
# @return [Boolean, nil]
|
46
46
|
mattr_accessor :preserve_job_records, default: false
|
47
47
|
|
48
48
|
# @!attribute [rw] retry_on_unhandled_error
|
@@ -51,10 +51,11 @@ module GoodJob
|
|
51
51
|
# If +true+, causes jobs to be re-queued and retried if they raise an instance of +StandardError+.
|
52
52
|
# If +false+, jobs will be discarded or marked as finished if they raise an instance of +StandardError+.
|
53
53
|
# Instances of +Exception+, like +SIGINT+, will *always* be retried, regardless of this attribute's value.
|
54
|
-
# @return [Boolean]
|
54
|
+
# @return [Boolean, nil]
|
55
55
|
mattr_accessor :retry_on_unhandled_error, default: true
|
56
56
|
|
57
57
|
# @deprecated Use {GoodJob#retry_on_unhandled_error} instead.
|
58
|
+
# @return [Boolean, nil]
|
58
59
|
def self.reperform_jobs_on_standard_error
|
59
60
|
ActiveSupport::Deprecation.warn(
|
60
61
|
"Calling 'GoodJob.reperform_jobs_on_standard_error' is deprecated. Please use 'retry_on_unhandled_error'"
|
@@ -63,6 +64,8 @@ module GoodJob
|
|
63
64
|
end
|
64
65
|
|
65
66
|
# @deprecated Use {GoodJob#retry_on_unhandled_error=} instead.
|
67
|
+
# @param value [Boolean]
|
68
|
+
# @return [Boolean]
|
66
69
|
def self.reperform_jobs_on_standard_error=(value)
|
67
70
|
ActiveSupport::Deprecation.warn(
|
68
71
|
"Setting 'GoodJob.reperform_jobs_on_standard_error=' is deprecated. Please use 'retry_on_unhandled_error='"
|
@@ -77,7 +80,7 @@ module GoodJob
|
|
77
80
|
# @example Send errors to Sentry
|
78
81
|
# # config/initializers/good_job.rb
|
79
82
|
# GoodJob.on_thread_error = -> (exception) { Raven.capture_exception(exception) }
|
80
|
-
# @return [
|
83
|
+
# @return [Proc, nil]
|
81
84
|
mattr_accessor :on_thread_error, default: nil
|
82
85
|
|
83
86
|
# Stop executing jobs.
|
@@ -93,13 +96,13 @@ module GoodJob
|
|
93
96
|
# @param wait [Boolean] whether to wait for shutdown
|
94
97
|
# @return [void]
|
95
98
|
def self.shutdown(timeout: -1, wait: nil)
|
96
|
-
timeout = if wait.
|
99
|
+
timeout = if wait.nil?
|
100
|
+
timeout
|
101
|
+
else
|
97
102
|
ActiveSupport::Deprecation.warn(
|
98
103
|
"Using `GoodJob.shutdown` with `wait:` kwarg is deprecated; use `timeout:` kwarg instead e.g. GoodJob.shutdown(timeout: #{wait ? '-1' : 'nil'})"
|
99
104
|
)
|
100
105
|
wait ? -1 : nil
|
101
|
-
else
|
102
|
-
timeout
|
103
106
|
end
|
104
107
|
|
105
108
|
executables = Array(Notifier.instances) + Array(Poller.instances) + Array(Scheduler.instances)
|
@@ -119,6 +122,7 @@ module GoodJob
|
|
119
122
|
# When forking processes you should shut down these background threads before forking, and restart them after forking.
|
120
123
|
# For example, you should use +shutdown+ and +restart+ when using async execution mode with Puma.
|
121
124
|
# See the {file:README.md#executing-jobs-async--in-process} for more explanation and examples.
|
125
|
+
# @param timeout [Numeric, nil] Seconds to wait for active threads to finish.
|
122
126
|
# @return [void]
|
123
127
|
def self.restart(timeout: -1)
|
124
128
|
executables = Array(Notifier.instances) + Array(Poller.instances) + Array(Scheduler.instances)
|
@@ -126,7 +130,7 @@ module GoodJob
|
|
126
130
|
end
|
127
131
|
|
128
132
|
# Sends +#shutdown+ or +#restart+ to executable objects ({GoodJob::Notifier}, {GoodJob::Poller}, {GoodJob::Scheduler})
|
129
|
-
# @param executables [Array<
|
133
|
+
# @param executables [Array<Notifier, Poller, Scheduler, MultiScheduler>] Objects to shut down.
|
130
134
|
# @param method_name [:symbol] Method to call, e.g. +:shutdown+ or +:restart+.
|
131
135
|
# @param timeout [nil,Numeric]
|
132
136
|
# @return [void]
|
data/lib/good_job/adapter.rb
CHANGED
@@ -6,7 +6,7 @@ module GoodJob
|
|
6
6
|
# Valid execution modes.
|
7
7
|
EXECUTION_MODES = [:async, :async_server, :external, :inline].freeze
|
8
8
|
|
9
|
-
# @param execution_mode [
|
9
|
+
# @param execution_mode [Symbol, nil] 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.
|
@@ -19,9 +19,9 @@ module GoodJob
|
|
19
19
|
# - +development+ and +test+: +:inline+
|
20
20
|
# - +production+ and all other environments: +:external+
|
21
21
|
#
|
22
|
-
# @param max_threads [
|
23
|
-
# @param queues [
|
24
|
-
# @param poll_interval [
|
22
|
+
# @param max_threads [Integer, nil] sets the number of threads per scheduler to use when +execution_mode+ is set to +:async+. The +queues+ parameter can specify a number of threads for each group of queues which will override this value. You can also set this with the environment variable +GOOD_JOB_MAX_THREADS+. Defaults to +5+.
|
23
|
+
# @param queues [String, nil] determines which queues to execute jobs from when +execution_mode+ is set to +:async+. See {file:README.md#optimize-queues-threads-and-processes} for more details on the format of this string. You can also set this with the environment variable +GOOD_JOB_QUEUES+. Defaults to +"*"+.
|
24
|
+
# @param poll_interval [Integer, nil] 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+. Defaults to +1+.
|
25
25
|
def initialize(execution_mode: nil, queues: nil, max_threads: nil, poll_interval: nil)
|
26
26
|
if caller[0..4].find { |c| c.include?("/config/application.rb") || c.include?("/config/environments/") }
|
27
27
|
ActiveSupport::Deprecation.warn(<<~DEPRECATION)
|
@@ -70,7 +70,7 @@ module GoodJob
|
|
70
70
|
# Enqueues an ActiveJob job to be run at a specific time.
|
71
71
|
# For use by Rails; you should generally not call this directly.
|
72
72
|
# @param active_job [ActiveJob::Base] the job to be enqueued from +#perform_later+
|
73
|
-
# @param timestamp [Integer] the epoch time to perform the job
|
73
|
+
# @param timestamp [Integer, nil] the epoch time to perform the job
|
74
74
|
# @return [GoodJob::Job]
|
75
75
|
def enqueue_at(active_job, timestamp)
|
76
76
|
good_job = GoodJob::Job.enqueue(
|
@@ -97,22 +97,21 @@ module GoodJob
|
|
97
97
|
end
|
98
98
|
|
99
99
|
# Shut down the thread pool executors.
|
100
|
-
# @param timeout [nil, Numeric] Seconds to wait for active threads.
|
101
|
-
#
|
100
|
+
# @param timeout [nil, Numeric, Symbol] Seconds to wait for active threads.
|
102
101
|
# * +nil+, the scheduler will trigger a shutdown but not wait for it to complete.
|
103
102
|
# * +-1+, the scheduler will wait until the shutdown is complete.
|
104
103
|
# * +0+, the scheduler will immediately shutdown and stop any threads.
|
105
104
|
# * A positive number will wait that many seconds before stopping any remaining active threads.
|
106
|
-
# @param wait [Boolean] Deprecated. Use +timeout:+ instead.
|
105
|
+
# @param wait [Boolean, nil] Deprecated. Use +timeout:+ instead.
|
107
106
|
# @return [void]
|
108
107
|
def shutdown(timeout: :default, wait: nil)
|
109
|
-
timeout = if wait.
|
108
|
+
timeout = if wait.nil?
|
109
|
+
timeout
|
110
|
+
else
|
110
111
|
ActiveSupport::Deprecation.warn(
|
111
112
|
"Using `GoodJob::Adapter.shutdown` with `wait:` kwarg is deprecated; use `timeout:` kwarg instead e.g. GoodJob::Adapter.shutdown(timeout: #{wait ? '-1' : 'nil'})"
|
112
113
|
)
|
113
114
|
wait ? -1 : nil
|
114
|
-
else
|
115
|
-
timeout
|
116
115
|
end
|
117
116
|
|
118
117
|
timeout = if timeout == :default
|
@@ -126,18 +125,21 @@ module GoodJob
|
|
126
125
|
end
|
127
126
|
|
128
127
|
# Whether in +:async+ execution mode.
|
128
|
+
# @return [Boolean]
|
129
129
|
def execute_async?
|
130
130
|
@configuration.execution_mode == :async ||
|
131
131
|
@configuration.execution_mode == :async_server && in_server_process?
|
132
132
|
end
|
133
133
|
|
134
134
|
# Whether in +:external+ execution mode.
|
135
|
+
# @return [Boolean]
|
135
136
|
def execute_externally?
|
136
137
|
@configuration.execution_mode == :external ||
|
137
138
|
@configuration.execution_mode == :async_server && !in_server_process?
|
138
139
|
end
|
139
140
|
|
140
141
|
# Whether in +:inline+ execution mode.
|
142
|
+
# @return [Boolean]
|
141
143
|
def execute_inline?
|
142
144
|
@configuration.execution_mode == :inline
|
143
145
|
end
|
@@ -145,6 +147,7 @@ module GoodJob
|
|
145
147
|
private
|
146
148
|
|
147
149
|
# Whether running in a web server process.
|
150
|
+
# @return [Boolean, nil]
|
148
151
|
def in_server_process?
|
149
152
|
return @_in_server_process if defined? @_in_server_process
|
150
153
|
|
@@ -84,9 +84,9 @@ module GoodJob
|
|
84
84
|
# on the format of this string.
|
85
85
|
# @return [String]
|
86
86
|
def queue_string
|
87
|
-
options[:queues] ||
|
88
|
-
rails_config[:queues] ||
|
89
|
-
env['GOOD_JOB_QUEUES'] ||
|
87
|
+
options[:queues].presence ||
|
88
|
+
rails_config[:queues].presence ||
|
89
|
+
env['GOOD_JOB_QUEUES'].presence ||
|
90
90
|
'*'
|
91
91
|
end
|
92
92
|
|
@@ -3,7 +3,6 @@ require 'active_support/core_ext/module/attribute_accessors_per_thread'
|
|
3
3
|
module GoodJob
|
4
4
|
# Thread-local attributes for passing values from Instrumentation.
|
5
5
|
# (Cannot use ActiveSupport::CurrentAttributes because ActiveJob resets it)
|
6
|
-
|
7
6
|
module CurrentExecution
|
8
7
|
# @!attribute [rw] error_on_retry
|
9
8
|
# @!scope class
|
data/lib/good_job/daemon.rb
CHANGED
@@ -13,6 +13,7 @@ module GoodJob
|
|
13
13
|
end
|
14
14
|
|
15
15
|
# Daemonizes the current process and writes out a pidfile.
|
16
|
+
# @return [void]
|
16
17
|
def daemonize
|
17
18
|
check_pid
|
18
19
|
Process.daemon
|
@@ -21,6 +22,7 @@ module GoodJob
|
|
21
22
|
|
22
23
|
private
|
23
24
|
|
25
|
+
# @return [void]
|
24
26
|
def write_pid
|
25
27
|
File.open(pidfile, ::File::CREAT | ::File::EXCL | ::File::WRONLY) { |f| f.write(Process.pid.to_s) }
|
26
28
|
at_exit { File.delete(pidfile) if File.exist?(pidfile) }
|
@@ -29,10 +31,12 @@ module GoodJob
|
|
29
31
|
retry
|
30
32
|
end
|
31
33
|
|
34
|
+
# @return [void]
|
32
35
|
def delete_pid
|
33
36
|
File.delete(pidfile) if File.exist?(pidfile)
|
34
37
|
end
|
35
38
|
|
39
|
+
# @return [void]
|
36
40
|
def check_pid
|
37
41
|
case pid_status(pidfile)
|
38
42
|
when :running, :not_owned
|
@@ -42,6 +46,8 @@ module GoodJob
|
|
42
46
|
end
|
43
47
|
end
|
44
48
|
|
49
|
+
# @param pidfile [Pathname, String]
|
50
|
+
# @return [Symbol]
|
45
51
|
def pid_status(pidfile)
|
46
52
|
return :exited unless File.exist?(pidfile)
|
47
53
|
|
data/lib/good_job/job.rb
CHANGED
@@ -50,6 +50,14 @@ module GoodJob
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
+
# Get Jobs with given class name
|
54
|
+
# @!method with_job_class
|
55
|
+
# @!scope class
|
56
|
+
# @param string [String]
|
57
|
+
# Job class name
|
58
|
+
# @return [ActiveRecord::Relation]
|
59
|
+
scope :with_job_class, ->(job_class) { where("serialized_params->>'job_class' = ?", job_class) }
|
60
|
+
|
53
61
|
# Get Jobs that have not yet been completed.
|
54
62
|
# @!method unfinished
|
55
63
|
# @!scope class
|
@@ -94,6 +102,12 @@ module GoodJob
|
|
94
102
|
# @return [ActiveRecord::Relation]
|
95
103
|
scope :finished, ->(timestamp = nil) { timestamp ? where(arel_table['finished_at'].lteq(timestamp)) : where.not(finished_at: nil) }
|
96
104
|
|
105
|
+
# Get Jobs that started but not finished yet.
|
106
|
+
# @!method running
|
107
|
+
# @!scope class
|
108
|
+
# @return [ActiveRecord::Relation]
|
109
|
+
scope :running, -> { where.not(performed_at: nil).where(finished_at: nil) }
|
110
|
+
|
97
111
|
# Get Jobs on queues that match the given queue string.
|
98
112
|
# @!method queue_string(string)
|
99
113
|
# @!scope class
|
@@ -235,7 +249,7 @@ module GoodJob
|
|
235
249
|
|
236
250
|
private
|
237
251
|
|
238
|
-
# @return [
|
252
|
+
# @return [ExecutionResult]
|
239
253
|
def execute
|
240
254
|
params = serialized_params.merge(
|
241
255
|
"provider_job_id" => id
|
@@ -24,7 +24,7 @@ module GoodJob
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# Perform the next eligible job
|
27
|
-
# @return [
|
27
|
+
# @return [Object, nil] Returns job result or +nil+ if no job was found
|
28
28
|
def next
|
29
29
|
job_query.perform_with_advisory_lock
|
30
30
|
end
|
@@ -54,7 +54,7 @@ module GoodJob
|
|
54
54
|
# @param after [DateTime, Time, nil] future jobs scheduled after this time
|
55
55
|
# @param limit [Integer] number of future timestamps to return
|
56
56
|
# @param now_limit [Integer] number of past timestamps to return
|
57
|
-
# @return [Array<
|
57
|
+
# @return [Array<DateTime, Time>, nil]
|
58
58
|
def next_at(after: nil, limit: nil, now_limit: nil)
|
59
59
|
job_query.next_scheduled_at(after: after, limit: limit, now_limit: now_limit)
|
60
60
|
end
|
data/lib/good_job/lockable.rb
CHANGED
@@ -245,11 +245,8 @@ module GoodJob
|
|
245
245
|
|
246
246
|
private
|
247
247
|
|
248
|
-
|
249
|
-
|
250
|
-
self.class.send(:sanitize_sql_for_conditions, *args)
|
251
|
-
end
|
252
|
-
|
248
|
+
# @param query [String]
|
249
|
+
# @return [Boolean]
|
253
250
|
def pg_or_jdbc_query(query)
|
254
251
|
if Concurrent.on_jruby?
|
255
252
|
# Replace $1 bind parameters with ?
|
@@ -14,6 +14,7 @@ module GoodJob
|
|
14
14
|
|
15
15
|
# @!macro notification_responder
|
16
16
|
# Responds to the +$0.good_job+ notification.
|
17
|
+
# @param event [ActiveSupport::Notifications::Event]
|
17
18
|
# @return [void]
|
18
19
|
def create(event)
|
19
20
|
# FIXME: This method does not match any good_job notifications.
|
@@ -24,7 +25,7 @@ module GoodJob
|
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
|
-
#
|
28
|
+
# @!macro notification_responder
|
28
29
|
def finished_timer_task(event)
|
29
30
|
exception = event.payload[:error]
|
30
31
|
return unless exception
|
@@ -34,7 +35,7 @@ module GoodJob
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
|
-
#
|
38
|
+
# @!macro notification_responder
|
38
39
|
def finished_job_task(event)
|
39
40
|
exception = event.payload[:error]
|
40
41
|
return unless exception
|
@@ -44,7 +45,7 @@ module GoodJob
|
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
|
-
#
|
48
|
+
# @!macro notification_responder
|
48
49
|
def scheduler_create_pool(event)
|
49
50
|
max_threads = event.payload[:max_threads]
|
50
51
|
performer_name = event.payload[:performer_name]
|
@@ -55,7 +56,7 @@ module GoodJob
|
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
58
|
-
#
|
59
|
+
# @!macro notification_responder
|
59
60
|
def scheduler_shutdown_start(event)
|
60
61
|
process_id = event.payload[:process_id]
|
61
62
|
|
@@ -64,7 +65,7 @@ module GoodJob
|
|
64
65
|
end
|
65
66
|
end
|
66
67
|
|
67
|
-
#
|
68
|
+
# @!macro notification_responder
|
68
69
|
def scheduler_shutdown(event)
|
69
70
|
process_id = event.payload[:process_id]
|
70
71
|
|
@@ -73,7 +74,7 @@ module GoodJob
|
|
73
74
|
end
|
74
75
|
end
|
75
76
|
|
76
|
-
#
|
77
|
+
# @!macro notification_responder
|
77
78
|
def scheduler_restart_pools(event)
|
78
79
|
process_id = event.payload[:process_id]
|
79
80
|
|
@@ -82,7 +83,7 @@ module GoodJob
|
|
82
83
|
end
|
83
84
|
end
|
84
85
|
|
85
|
-
#
|
86
|
+
# @!macro notification_responder
|
86
87
|
def perform_job(event)
|
87
88
|
good_job = event.payload[:good_job]
|
88
89
|
process_id = event.payload[:process_id]
|
@@ -93,14 +94,14 @@ module GoodJob
|
|
93
94
|
end
|
94
95
|
end
|
95
96
|
|
96
|
-
#
|
97
|
-
def notifier_listen(
|
97
|
+
# @!macro notification_responder
|
98
|
+
def notifier_listen(event) # rubocop:disable Lint/UnusedMethodArgument
|
98
99
|
info do
|
99
100
|
"Notifier subscribed with LISTEN"
|
100
101
|
end
|
101
102
|
end
|
102
103
|
|
103
|
-
#
|
104
|
+
# @!macro notification_responder
|
104
105
|
def notifier_notified(event)
|
105
106
|
payload = event.payload[:payload]
|
106
107
|
|
@@ -109,7 +110,7 @@ module GoodJob
|
|
109
110
|
end
|
110
111
|
end
|
111
112
|
|
112
|
-
#
|
113
|
+
# @!macro notification_responder
|
113
114
|
def notifier_notify_error(event)
|
114
115
|
error = event.payload[:error]
|
115
116
|
|
@@ -118,14 +119,14 @@ module GoodJob
|
|
118
119
|
end
|
119
120
|
end
|
120
121
|
|
121
|
-
#
|
122
|
-
def notifier_unlisten(
|
122
|
+
# @!macro notification_responder
|
123
|
+
def notifier_unlisten(event) # rubocop:disable Lint/UnusedMethodArgument
|
123
124
|
info do
|
124
125
|
"Notifier unsubscribed with UNLISTEN"
|
125
126
|
end
|
126
127
|
end
|
127
128
|
|
128
|
-
#
|
129
|
+
# @!macro notification_responder
|
129
130
|
def cleanup_preserved_jobs(event)
|
130
131
|
timestamp = event.payload[:timestamp]
|
131
132
|
deleted_records_count = event.payload[:deleted_records_count]
|
@@ -4,31 +4,40 @@ module GoodJob
|
|
4
4
|
# @return [Array<Scheduler>] List of the scheduler delegates
|
5
5
|
attr_reader :schedulers
|
6
6
|
|
7
|
+
# @param schedulers [Array<Scheduler>]
|
7
8
|
def initialize(schedulers)
|
8
9
|
@schedulers = schedulers
|
9
10
|
end
|
10
11
|
|
11
12
|
# Delegates to {Scheduler#running?}.
|
13
|
+
# @return [Boolean, nil]
|
12
14
|
def running?
|
13
15
|
schedulers.all?(&:running?)
|
14
16
|
end
|
15
17
|
|
16
18
|
# Delegates to {Scheduler#shutdown?}.
|
19
|
+
# @return [Boolean, nil]
|
17
20
|
def shutdown?
|
18
21
|
schedulers.all?(&:shutdown?)
|
19
22
|
end
|
20
23
|
|
21
24
|
# Delegates to {Scheduler#shutdown}.
|
25
|
+
# @param timeout [Numeric, nil]
|
26
|
+
# @return [void]
|
22
27
|
def shutdown(timeout: -1)
|
23
28
|
GoodJob._shutdown_all(schedulers, timeout: timeout)
|
24
29
|
end
|
25
30
|
|
26
31
|
# Delegates to {Scheduler#restart}.
|
32
|
+
# @param timeout [Numeric, nil]
|
33
|
+
# @return [void]
|
27
34
|
def restart(timeout: -1)
|
28
35
|
GoodJob._shutdown_all(schedulers, :restart, timeout: timeout)
|
29
36
|
end
|
30
37
|
|
31
38
|
# Delegates to {Scheduler#create_thread}.
|
39
|
+
# @param state [Hash]
|
40
|
+
# @return [Boolean, nil]
|
32
41
|
def create_thread(state = nil)
|
33
42
|
results = []
|
34
43
|
|
data/lib/good_job/notifier.rb
CHANGED
@@ -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 [Array<GoodJob::
|
33
|
+
# @return [Array<GoodJob::Notifier>, nil]
|
34
34
|
cattr_reader :instances, default: [], instance_reader: false
|
35
35
|
|
36
36
|
# Send a message via Postgres NOTIFY
|
@@ -64,17 +64,19 @@ module GoodJob # :nodoc:
|
|
64
64
|
end
|
65
65
|
|
66
66
|
# Tests whether the notifier is running.
|
67
|
+
# @!method running?
|
67
68
|
# @return [true, false, nil]
|
68
69
|
delegate :running?, to: :executor, allow_nil: true
|
69
70
|
|
70
71
|
# Tests whether the scheduler is shutdown.
|
72
|
+
# @!method shutdown?
|
71
73
|
# @return [true, false, nil]
|
72
74
|
delegate :shutdown?, to: :executor, allow_nil: true
|
73
75
|
|
74
76
|
# Shut down the notifier.
|
75
77
|
# This stops the background LISTENing thread.
|
76
78
|
# Use {#shutdown?} to determine whether threads have stopped.
|
77
|
-
# @param timeout [
|
79
|
+
# @param timeout [Numeric, nil] Seconds to wait for active threads.
|
78
80
|
# * +nil+, the scheduler will trigger a shutdown but not wait for it to complete.
|
79
81
|
# * +-1+, the scheduler will wait until the shutdown is complete.
|
80
82
|
# * +0+, the scheduler will immediately shutdown and stop any threads.
|
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 [Array<GoodJob::Poller
|
19
|
+
# @return [Array<GoodJob::Poller>, nil]
|
20
20
|
cattr_reader :instances, default: [], instance_reader: false
|
21
21
|
|
22
22
|
# Creates GoodJob::Poller from a GoodJob::Configuration instance.
|
@@ -30,8 +30,8 @@ module GoodJob # :nodoc:
|
|
30
30
|
# @return [Array<#call, Array(Object, Symbol)>]
|
31
31
|
attr_reader :recipients
|
32
32
|
|
33
|
-
# @param recipients [Array
|
34
|
-
# @param poll_interval [
|
33
|
+
# @param recipients [Array<Proc, #call, Array(Object, Symbol)>]
|
34
|
+
# @param poll_interval [Integer, nil] number of seconds between polls
|
35
35
|
def initialize(*recipients, poll_interval: nil)
|
36
36
|
@recipients = Concurrent::Array.new(recipients)
|
37
37
|
|
@@ -72,7 +72,7 @@ module GoodJob # :nodoc:
|
|
72
72
|
|
73
73
|
# Restart the poller.
|
74
74
|
# When shutdown, start; or shutdown and start.
|
75
|
-
# @param timeout [
|
75
|
+
# @param timeout [Numeric, nil] Seconds to wait; shares same values as {#shutdown}.
|
76
76
|
# @return [void]
|
77
77
|
def restart(timeout: -1)
|
78
78
|
shutdown(timeout: timeout) if running?
|
@@ -81,6 +81,9 @@ module GoodJob # :nodoc:
|
|
81
81
|
|
82
82
|
# Invoked on completion of TimerTask task.
|
83
83
|
# @!visibility private
|
84
|
+
# @param time [Integer]
|
85
|
+
# @param executed_task [Object, nil]
|
86
|
+
# @param thread_error [Exception, nil]
|
84
87
|
# @return [void]
|
85
88
|
def timer_observer(time, executed_task, thread_error)
|
86
89
|
GoodJob.on_thread_error.call(thread_error) if thread_error && GoodJob.on_thread_error.respond_to?(:call)
|
@@ -89,8 +92,10 @@ module GoodJob # :nodoc:
|
|
89
92
|
|
90
93
|
private
|
91
94
|
|
95
|
+
# @return [Concurrent::TimerTask]
|
92
96
|
attr_reader :timer
|
93
97
|
|
98
|
+
# @return [void]
|
94
99
|
def create_timer
|
95
100
|
return if @timer_options[:execution_interval] <= 0
|
96
101
|
|
data/lib/good_job/scheduler.rb
CHANGED
@@ -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 [Array<GoodJob::Scheduler
|
33
|
+
# @return [Array<GoodJob::Scheduler>, nil]
|
34
34
|
cattr_reader :instances, default: [], instance_reader: false
|
35
35
|
|
36
36
|
# Creates GoodJob::Scheduler(s) and Performers from a GoodJob::Configuration instance.
|
@@ -82,17 +82,17 @@ module GoodJob # :nodoc:
|
|
82
82
|
end
|
83
83
|
|
84
84
|
# Tests whether the scheduler is running.
|
85
|
-
# @return [
|
85
|
+
# @return [Boolean, nil]
|
86
86
|
delegate :running?, to: :executor, allow_nil: true
|
87
87
|
|
88
88
|
# Tests whether the scheduler is shutdown.
|
89
|
-
# @return [
|
89
|
+
# @return [Boolean, nil]
|
90
90
|
delegate :shutdown?, to: :executor, allow_nil: true
|
91
91
|
|
92
92
|
# Shut down the scheduler.
|
93
93
|
# This stops all threads in the thread pool.
|
94
94
|
# Use {#shutdown?} to determine whether threads have stopped.
|
95
|
-
# @param timeout [
|
95
|
+
# @param timeout [Numeric, nil] Seconds to wait for actively executing jobs to finish
|
96
96
|
# * +nil+, the scheduler will trigger a shutdown but not wait for it to complete.
|
97
97
|
# * +-1+, the scheduler will wait until the shutdown is complete.
|
98
98
|
# * +0+, the scheduler will immediately shutdown and stop any active tasks.
|
@@ -128,8 +128,8 @@ module GoodJob # :nodoc:
|
|
128
128
|
end
|
129
129
|
|
130
130
|
# Wakes a thread to allow the performer to execute a task.
|
131
|
-
# @param state [
|
132
|
-
# @return [
|
131
|
+
# @param state [Hash, nil] Contextual information for the performer. See {JobPerformer#next?}.
|
132
|
+
# @return [Boolean, nil] Whether work was started.
|
133
133
|
#
|
134
134
|
# * +nil+ if the scheduler is unable to take new work, for example if the thread pool is shut down or at capacity.
|
135
135
|
# * +true+ if the performer started executing work.
|
@@ -215,6 +215,7 @@ module GoodJob # :nodoc:
|
|
215
215
|
|
216
216
|
attr_reader :performer, :executor, :timer_set
|
217
217
|
|
218
|
+
# @return [void]
|
218
219
|
def create_executor
|
219
220
|
instrument("scheduler_create_pool", { performer_name: performer.name, max_threads: @executor_options[:max_threads] }) do
|
220
221
|
@timer_set = TimerSet.new
|
@@ -222,6 +223,8 @@ module GoodJob # :nodoc:
|
|
222
223
|
end
|
223
224
|
end
|
224
225
|
|
226
|
+
# @param delay [Integer]
|
227
|
+
# @return [void]
|
225
228
|
def create_task(delay = 0)
|
226
229
|
future = Concurrent::ScheduledTask.new(delay, args: [performer], executor: executor, timer_set: timer_set) do |thr_performer|
|
227
230
|
Rails.application.executor.wrap do
|
@@ -232,6 +235,9 @@ module GoodJob # :nodoc:
|
|
232
235
|
future.execute
|
233
236
|
end
|
234
237
|
|
238
|
+
# @param name [String]
|
239
|
+
# @param payload [Hash]
|
240
|
+
# @return [void]
|
235
241
|
def instrument(name, payload = {}, &block)
|
236
242
|
payload = payload.reverse_merge({
|
237
243
|
scheduler: self,
|
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.9.
|
4
|
+
version: 1.9.4
|
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-05-
|
11
|
+
date: 2021-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|