rocketjob 5.1.1 → 5.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/rocketjob +2 -2
- data/bin/rocketjob_batch_perf +1 -1
- data/bin/rocketjob_perf +1 -1
- data/lib/rocket_job/active_worker.rb +1 -0
- data/lib/rocket_job/batch.rb +16 -17
- data/lib/rocket_job/batch/callbacks.rb +1 -2
- data/lib/rocket_job/batch/io.rb +10 -6
- data/lib/rocket_job/batch/logger.rb +2 -2
- data/lib/rocket_job/batch/lower_priority.rb +2 -2
- data/lib/rocket_job/batch/model.rb +23 -23
- data/lib/rocket_job/batch/performance.rb +19 -21
- data/lib/rocket_job/batch/result.rb +1 -1
- data/lib/rocket_job/batch/results.rb +1 -1
- data/lib/rocket_job/batch/state_machine.rb +5 -6
- data/lib/rocket_job/batch/statistics.rb +10 -8
- data/lib/rocket_job/batch/tabular.rb +2 -2
- data/lib/rocket_job/batch/tabular/input.rb +11 -7
- data/lib/rocket_job/batch/tabular/output.rb +1 -1
- data/lib/rocket_job/batch/throttle.rb +11 -30
- data/lib/rocket_job/batch/{throttle_running_slices.rb → throttle_running_workers.rb} +13 -10
- data/lib/rocket_job/batch/worker.rb +102 -85
- data/lib/rocket_job/cli.rb +57 -54
- data/lib/rocket_job/config.rb +8 -10
- data/lib/rocket_job/dirmon_entry.rb +13 -10
- data/lib/rocket_job/event.rb +16 -16
- data/lib/rocket_job/extensions/mongo/logging.rb +2 -2
- data/lib/rocket_job/extensions/mongoid/clients/options.rb +2 -2
- data/lib/rocket_job/extensions/mongoid/contextual/mongo.rb +4 -2
- data/lib/rocket_job/extensions/mongoid/factory.rb +13 -5
- data/lib/rocket_job/extensions/rocket_job_adapter.rb +2 -1
- data/lib/rocket_job/job_exception.rb +0 -3
- data/lib/rocket_job/jobs/dirmon_job.rb +4 -4
- data/lib/rocket_job/jobs/housekeeping_job.rb +7 -7
- data/lib/rocket_job/jobs/on_demand_batch_job.rb +14 -4
- data/lib/rocket_job/jobs/on_demand_job.rb +3 -3
- data/lib/rocket_job/jobs/performance_job.rb +1 -1
- data/lib/rocket_job/jobs/re_encrypt/relational_job.rb +11 -10
- data/lib/rocket_job/jobs/upload_file_job.rb +9 -5
- data/lib/rocket_job/performance.rb +24 -22
- data/lib/rocket_job/plugins/cron.rb +7 -3
- data/lib/rocket_job/plugins/document.rb +7 -5
- data/lib/rocket_job/plugins/job/callbacks.rb +1 -1
- data/lib/rocket_job/plugins/job/logger.rb +3 -3
- data/lib/rocket_job/plugins/job/model.rb +34 -27
- data/lib/rocket_job/plugins/job/persistence.rb +7 -34
- data/lib/rocket_job/plugins/job/state_machine.rb +5 -4
- data/lib/rocket_job/plugins/job/throttle.rb +12 -28
- data/lib/rocket_job/plugins/job/throttle_running_jobs.rb +2 -2
- data/lib/rocket_job/plugins/job/worker.rb +22 -70
- data/lib/rocket_job/plugins/processing_window.rb +5 -4
- data/lib/rocket_job/plugins/restart.rb +3 -3
- data/lib/rocket_job/plugins/retry.rb +2 -2
- data/lib/rocket_job/plugins/singleton.rb +1 -2
- data/lib/rocket_job/plugins/state_machine.rb +4 -4
- data/lib/rocket_job/plugins/transaction.rb +1 -1
- data/lib/rocket_job/rocket_job.rb +5 -4
- data/lib/rocket_job/server.rb +2 -2
- data/lib/rocket_job/server/model.rb +14 -13
- data/lib/rocket_job/server/state_machine.rb +1 -2
- data/lib/rocket_job/sliced/compressed_slice.rb +4 -4
- data/lib/rocket_job/sliced/encrypted_slice.rb +4 -4
- data/lib/rocket_job/sliced/input.rb +16 -16
- data/lib/rocket_job/sliced/output.rb +2 -2
- data/lib/rocket_job/sliced/slice.rb +43 -20
- data/lib/rocket_job/sliced/slices.rb +14 -11
- data/lib/rocket_job/subscriber.rb +6 -6
- data/lib/rocket_job/subscribers/logger.rb +3 -3
- data/lib/rocket_job/supervisor.rb +12 -12
- data/lib/rocket_job/supervisor/shutdown.rb +7 -7
- data/lib/rocket_job/throttle_definition.rb +37 -0
- data/lib/rocket_job/throttle_definitions.rb +39 -0
- data/lib/rocket_job/version.rb +1 -1
- data/lib/rocket_job/worker.rb +116 -34
- data/lib/rocket_job/worker_pool.rb +6 -6
- data/lib/rocketjob.rb +72 -76
- metadata +16 -18
- data/lib/rocket_job/extensions/mongoid_5/clients/options.rb +0 -38
- data/lib/rocket_job/extensions/mongoid_5/contextual/mongo.rb +0 -64
- data/lib/rocket_job/extensions/mongoid_5/factory.rb +0 -13
@@ -13,8 +13,8 @@ module RocketJob
|
|
13
13
|
#
|
14
14
|
# tabular.render(row)
|
15
15
|
class Tabular
|
16
|
-
autoload :Input,
|
17
|
-
autoload :Output,
|
16
|
+
autoload :Input, "rocket_job/batch/tabular/input"
|
17
|
+
autoload :Output, "rocket_job/batch/tabular/output"
|
18
18
|
|
19
19
|
def initialize(map)
|
20
20
|
@map = map
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_support/concern"
|
2
2
|
|
3
3
|
module RocketJob
|
4
4
|
module Batch
|
@@ -53,7 +53,7 @@ module RocketJob
|
|
53
53
|
input_stream = stream.nil? ? nil : IOStreams.new(stream)
|
54
54
|
|
55
55
|
if stream && (tabular_input_type == :text)
|
56
|
-
input_stream.option_or_stream(:encode, encoding:
|
56
|
+
input_stream.option_or_stream(:encode, encoding: "UTF-8", cleaner: :printable, replace: "")
|
57
57
|
end
|
58
58
|
|
59
59
|
# If an input header is not required, then we don't extract it'
|
@@ -67,14 +67,14 @@ module RocketJob
|
|
67
67
|
|
68
68
|
case tabular_input_mode
|
69
69
|
when :line
|
70
|
-
parse_header =
|
70
|
+
parse_header = lambda do |line|
|
71
71
|
tabular_input.parse_header(line)
|
72
72
|
tabular_input_cleanse_header
|
73
73
|
self.tabular_input_header = tabular_input.header.columns
|
74
74
|
end
|
75
75
|
super(input_stream, on_first: parse_header, stream_mode: :line, **args, &block)
|
76
76
|
when :array, :row
|
77
|
-
set_header =
|
77
|
+
set_header = lambda do |row|
|
78
78
|
tabular_input.header.columns = row
|
79
79
|
tabular_input_cleanse_header
|
80
80
|
self.tabular_input_header = tabular_input.header.columns
|
@@ -101,19 +101,23 @@ module RocketJob
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def tabular_input_render
|
104
|
-
|
104
|
+
unless tabular_input_header.blank? && tabular_input.header?
|
105
|
+
@rocket_job_input = tabular_input.record_parse(@rocket_job_input)
|
106
|
+
end
|
105
107
|
end
|
106
108
|
|
107
109
|
# Cleanse custom input header if supplied.
|
108
110
|
def tabular_input_cleanse_header
|
109
111
|
ignored_columns = tabular_input.header.cleanse!
|
110
|
-
logger.warn(
|
112
|
+
logger.warn("Stripped out invalid columns from custom header", ignored_columns) unless ignored_columns.empty?
|
111
113
|
|
112
114
|
self.tabular_input_header = tabular_input.header.columns
|
113
115
|
end
|
114
116
|
|
115
117
|
def tabular_input_header_present
|
116
|
-
|
118
|
+
if tabular_input_header.present? || !tabular_input.header? || (tabular_input_mode == :hash || tabular_input_mode == :record)
|
119
|
+
return
|
120
|
+
end
|
117
121
|
|
118
122
|
errors.add(:tabular_input_header, "is required when tabular_input_format is #{tabular_input_format.inspect}")
|
119
123
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_support/concern"
|
2
2
|
|
3
3
|
module RocketJob
|
4
4
|
module Batch
|
@@ -31,7 +31,6 @@ module RocketJob
|
|
31
31
|
|
32
32
|
included do
|
33
33
|
class_attribute :rocket_job_batch_throttles
|
34
|
-
self.rocket_job_batch_throttles = []
|
35
34
|
end
|
36
35
|
|
37
36
|
module ClassMethods
|
@@ -48,44 +47,26 @@ module RocketJob
|
|
48
47
|
#
|
49
48
|
# Note: Throttles are executed in the order they are defined.
|
50
49
|
def define_batch_throttle(method_name, filter: :throttle_filter_class)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
raise(ArgumentError, "Cannot define #{method_name} twice, undefine previous throttle first")
|
56
|
-
end
|
57
|
-
|
58
|
-
self.rocket_job_batch_throttles += [ThrottleDefinition.new(method_name, filter)]
|
50
|
+
# Duplicate to prevent modifying parent class throttles
|
51
|
+
definitions = rocket_job_batch_throttles ? rocket_job_batch_throttles.dup : ThrottleDefinitions.new
|
52
|
+
definitions.add(method_name, filter)
|
53
|
+
self.rocket_job_batch_throttles = definitions
|
59
54
|
end
|
60
55
|
|
61
56
|
# Undefine a previously defined throttle
|
62
57
|
def undefine_batch_throttle(method_name)
|
63
|
-
|
58
|
+
return unless rocket_job_batch_throttles
|
59
|
+
|
60
|
+
definitions = rocket_job_batch_throttles.dup
|
61
|
+
definitions.remove(method_name)
|
62
|
+
self.rocket_job_batch_throttles = definitions
|
64
63
|
end
|
65
64
|
|
66
65
|
# Has a throttle been defined?
|
67
66
|
def batch_throttle?(method_name)
|
68
|
-
rocket_job_batch_throttles.
|
67
|
+
rocket_job_batch_throttles.exist?(method_name)
|
69
68
|
end
|
70
69
|
end
|
71
|
-
|
72
|
-
private
|
73
|
-
|
74
|
-
ThrottleDefinition = Struct.new(:method_name, :filter)
|
75
|
-
|
76
|
-
# Returns the matching filter, or nil if no throttles were triggered.
|
77
|
-
def rocket_job_batch_evaluate_throttles(slice)
|
78
|
-
rocket_job_batch_throttles.each do |throttle|
|
79
|
-
throttle_exceeded = method(throttle.method_name).arity == 0 ? send(throttle.method_name) : send(throttle.method_name, slice)
|
80
|
-
next unless throttle_exceeded
|
81
|
-
|
82
|
-
logger.debug { "Batch Throttle: #{throttle.method_name} has been exceeded. #{self.class.name}:#{id}" }
|
83
|
-
filter = throttle.filter
|
84
|
-
return filter.is_a?(Proc) ? filter.call(self) : send(filter)
|
85
|
-
end
|
86
|
-
nil
|
87
|
-
end
|
88
|
-
|
89
70
|
end
|
90
71
|
end
|
91
72
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_support/concern"
|
2
2
|
|
3
3
|
module RocketJob
|
4
4
|
module Batch
|
@@ -9,7 +9,7 @@ module RocketJob
|
|
9
9
|
# include RocketJob::Batch
|
10
10
|
#
|
11
11
|
# # Maximum number of slices to process at the same time for each running instance.
|
12
|
-
# self.
|
12
|
+
# self.throttle_running_workers = 25
|
13
13
|
#
|
14
14
|
# def perform(record)
|
15
15
|
# # ....
|
@@ -28,28 +28,31 @@ module RocketJob
|
|
28
28
|
# 0 or nil : No limits in place
|
29
29
|
#
|
30
30
|
# Default: nil
|
31
|
-
module
|
31
|
+
module ThrottleRunningWorkers
|
32
32
|
extend ActiveSupport::Concern
|
33
33
|
|
34
34
|
included do
|
35
|
-
field :
|
35
|
+
field :throttle_running_workers, type: Integer, class_attribute: true, user_editable: true, copy_on_restart: true
|
36
36
|
|
37
|
-
validates :
|
37
|
+
validates :throttle_running_workers, numericality: {greater_than_or_equal_to: 0}, allow_nil: true
|
38
38
|
|
39
|
-
define_batch_throttle :
|
39
|
+
define_batch_throttle :throttle_running_workers_exceeded?, filter: :throttle_filter_id
|
40
|
+
|
41
|
+
# Deprecated. For backward compatibility.
|
42
|
+
alias_method :throttle_running_slices, :throttle_running_workers
|
43
|
+
alias_method :throttle_running_slices=, :throttle_running_workers=
|
40
44
|
end
|
41
45
|
|
42
46
|
private
|
43
47
|
|
44
48
|
# Returns [Boolean] whether the throttle for this job has been exceeded
|
45
|
-
def
|
46
|
-
return unless
|
49
|
+
def throttle_running_workers_exceeded?(slice)
|
50
|
+
return unless throttle_running_workers&.positive?
|
47
51
|
|
48
52
|
input.running.with(read: {mode: :primary}) do |conn|
|
49
|
-
conn.where(:id.ne => slice.id).count >=
|
53
|
+
conn.where(:id.ne => slice.id).count >= throttle_running_workers
|
50
54
|
end
|
51
55
|
end
|
52
|
-
|
53
56
|
end
|
54
57
|
end
|
55
58
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_support/concern"
|
2
2
|
|
3
3
|
module RocketJob
|
4
4
|
module Batch
|
@@ -16,10 +16,10 @@ module RocketJob
|
|
16
16
|
|
17
17
|
# Processes records in each available slice for this job. Slices are processed
|
18
18
|
# one at a time to allow for concurrent calls to this method to increase
|
19
|
-
# throughput. Processing will continue until there are no more
|
19
|
+
# throughput. Processing will continue until there are no more slices available
|
20
20
|
# for this job.
|
21
21
|
#
|
22
|
-
# Returns [true|false] whether
|
22
|
+
# Returns [true|false] whether any work was performed.
|
23
23
|
#
|
24
24
|
# Slices are destroyed after their records are successfully processed
|
25
25
|
#
|
@@ -33,36 +33,34 @@ module RocketJob
|
|
33
33
|
# Mongo connection failure occurs.
|
34
34
|
#
|
35
35
|
# Thread-safe, can be called by multiple threads at the same time
|
36
|
-
def rocket_job_work(worker, re_raise_exceptions = false
|
37
|
-
raise
|
36
|
+
def rocket_job_work(worker, re_raise_exceptions = false)
|
37
|
+
raise "Job must be started before calling #rocket_job_work" unless running?
|
38
|
+
|
38
39
|
start_time = Time.now
|
39
40
|
if sub_state != :processing
|
40
|
-
|
41
|
+
fail_on_exception!(re_raise_exceptions) { rocket_job_batch_callbacks(worker) }
|
41
42
|
return false unless running?
|
42
43
|
end
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
slice.
|
50
|
-
|
45
|
+
SemanticLogger.named_tagged(job: id.to_s) do
|
46
|
+
until worker.shutdown?
|
47
|
+
if slice = input.next_slice(worker.name)
|
48
|
+
# Grab a slice before checking the throttle to reduce concurrency race condition.
|
49
|
+
return true if slice.fail_on_exception!(re_raise_exceptions) { rocket_job_batch_throttled?(slice, worker) }
|
50
|
+
next if slice.failed?
|
51
|
+
|
52
|
+
slice.fail_on_exception!(re_raise_exceptions) { rocket_job_process_slice(slice) }
|
53
|
+
elsif record_count && rocket_job_batch_complete?(worker.name)
|
54
|
+
return false
|
55
|
+
else
|
56
|
+
logger.debug "No more work available for this job"
|
57
|
+
worker.add_to_current_filter(throttle_filter_id)
|
51
58
|
return true
|
52
59
|
end
|
53
60
|
|
54
|
-
|
55
|
-
|
56
|
-
end
|
57
|
-
else
|
58
|
-
break if record_count && rocket_job_batch_complete?(worker.name)
|
59
|
-
logger.debug 'No more work available for this job'
|
60
|
-
self.class.send(:rocket_job_merge_filter, filter, throttle_filter_id)
|
61
|
-
return true
|
61
|
+
# Allow new jobs with a higher priority to interrupt this job
|
62
|
+
break if (Time.now - start_time) >= Config.re_check_seconds
|
62
63
|
end
|
63
|
-
|
64
|
-
# Allow new jobs with a higher priority to interrupt this job
|
65
|
-
break if (Time.now - start_time) >= Config.re_check_seconds
|
66
64
|
end
|
67
65
|
false
|
68
66
|
end
|
@@ -76,27 +74,26 @@ module RocketJob
|
|
76
74
|
#
|
77
75
|
# Note: The slice will be removed from processing when this method completes
|
78
76
|
def work_first_slice(&block)
|
79
|
-
raise
|
80
|
-
|
77
|
+
raise "#work_first_slice can only be called from within before_batch callbacks" unless sub_state == :before
|
78
|
+
|
79
|
+
# TODO: Make these settings configurable
|
81
80
|
count = 0
|
82
81
|
wait_seconds = 5
|
83
|
-
while
|
82
|
+
while input.first.nil?
|
84
83
|
break if count > 10
|
84
|
+
|
85
85
|
logger.info "First slice has not arrived yet, sleeping for #{wait_seconds} seconds"
|
86
86
|
sleep wait_seconds
|
87
87
|
count += 1
|
88
88
|
end
|
89
89
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
# No records processed
|
98
|
-
0
|
99
|
-
end
|
90
|
+
slice = input.first
|
91
|
+
# No records processed
|
92
|
+
return 0 unless slice
|
93
|
+
|
94
|
+
# TODO: Persist that the first slice is being processed by this worker
|
95
|
+
slice.start
|
96
|
+
rocket_job_process_slice(slice, &block)
|
100
97
|
end
|
101
98
|
|
102
99
|
# Returns [Array<ActiveWorker>] All workers actively working on this job
|
@@ -119,50 +116,73 @@ module RocketJob
|
|
119
116
|
|
120
117
|
private
|
121
118
|
|
119
|
+
def rocket_job_batch_throttled?(slice, worker)
|
120
|
+
filter = self.class.rocket_job_batch_throttles.matching_filter(self, slice)
|
121
|
+
return false unless filter
|
122
|
+
|
123
|
+
# Restore retrieved slice so that other workers can process it later.
|
124
|
+
slice.set(worker_name: nil, state: :queued, started_at: nil)
|
125
|
+
worker.add_to_current_filter(filter)
|
126
|
+
true
|
127
|
+
end
|
128
|
+
|
122
129
|
# Process a single slice from Mongo
|
123
130
|
# Once the slice has been successfully processed it will be removed from the input collection
|
124
131
|
# Returns [Integer] the number of records successfully processed
|
125
|
-
def rocket_job_process_slice(slice
|
126
|
-
|
132
|
+
def rocket_job_process_slice(slice)
|
133
|
+
# TODO: Skip records already processed
|
127
134
|
@rocket_job_record_number = slice.first_record_number || 0
|
128
135
|
@rocket_job_slice = slice
|
129
|
-
|
136
|
+
|
137
|
+
processed_records = 0
|
138
|
+
run_callbacks(:slice) do
|
139
|
+
# Allow before_slice callbacks to fail, complete or abort this slice.
|
140
|
+
return 0 unless running?
|
141
|
+
|
130
142
|
RocketJob::Sliced::Writer::Output.collect(self, slice) do |writer|
|
131
143
|
slice.each do |record|
|
132
|
-
slice_record_number += 1
|
133
144
|
SemanticLogger.named_tagged(record: @rocket_job_record_number) do
|
134
|
-
|
135
|
-
|
136
|
-
else
|
137
|
-
# Allows @rocket_job_input to be modified by before/around callbacks
|
138
|
-
@rocket_job_input = record
|
139
|
-
# Allow callbacks to fail, complete or abort the job
|
140
|
-
if running?
|
141
|
-
if block_given?
|
142
|
-
run_callbacks(:perform) { @rocket_job_output = yield(@rocket_job_input) }
|
143
|
-
else
|
144
|
-
# Allows @rocket_job_output to be modified by after/around callbacks
|
145
|
-
run_callbacks(:perform) { @rocket_job_output = perform(@rocket_job_input) }
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
writer << @rocket_job_output
|
145
|
+
writer << rocket_job_batch_perform(slice, record)
|
146
|
+
processed_records += 1
|
150
147
|
end
|
151
|
-
# JRuby
|
148
|
+
# JRuby thinks self.rocket_job_record_number= is private and cannot be accessed
|
152
149
|
@rocket_job_record_number += 1
|
153
150
|
end
|
154
151
|
end
|
155
|
-
@
|
152
|
+
@rocket_job_slice = nil
|
153
|
+
@rocket_job_record_number = nil
|
156
154
|
end
|
157
155
|
|
158
156
|
# On successful completion remove the slice from the input queue
|
159
|
-
# TODO
|
157
|
+
# TODO: Add option to complete slice instead of destroying it to retain input data.
|
160
158
|
slice.destroy
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
159
|
+
processed_records
|
160
|
+
end
|
161
|
+
|
162
|
+
# Perform a single record within the current slice.
|
163
|
+
def rocket_job_batch_perform(slice, record)
|
164
|
+
slice.processing_record_number ||= 0
|
165
|
+
slice.processing_record_number += 1
|
166
|
+
|
167
|
+
return block_given? ? yield(record) : perform(record) if _perform_callbacks.empty?
|
168
|
+
|
169
|
+
# @rocket_job_input and @rocket_job_output can be modified by before/around callbacks
|
170
|
+
@rocket_job_input = record
|
171
|
+
@rocket_job_output = nil
|
172
|
+
|
173
|
+
run_callbacks(:perform) do
|
174
|
+
@rocket_job_output =
|
175
|
+
if block_given?
|
176
|
+
yield(@rocket_job_input)
|
177
|
+
else
|
178
|
+
perform(@rocket_job_input)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
@rocket_job_input = nil
|
183
|
+
result = @rocket_job_output
|
184
|
+
@rocket_job_output = nil
|
185
|
+
result
|
166
186
|
end
|
167
187
|
|
168
188
|
# Checks for completion and runs after_batch if defined
|
@@ -174,7 +194,7 @@ module RocketJob
|
|
174
194
|
# Only failed slices left?
|
175
195
|
input_count = input.count
|
176
196
|
failed_count = input.failed.count
|
177
|
-
if
|
197
|
+
if failed_count.positive? && (input_count == failed_count)
|
178
198
|
# Reload to pull in any counters or other data that was modified.
|
179
199
|
reload unless new_record?
|
180
200
|
if may_fail?
|
@@ -185,9 +205,9 @@ module RocketJob
|
|
185
205
|
result = self.class.with(write: {w: 1}) do |query|
|
186
206
|
query.
|
187
207
|
where(id: id, state: :running, sub_state: :processing).
|
188
|
-
update({
|
208
|
+
update({"$set" => {state: :failed, worker_name: worker_name}})
|
189
209
|
end
|
190
|
-
fail_job = false unless result.modified_count
|
210
|
+
fail_job = false unless result.modified_count.positive?
|
191
211
|
end
|
192
212
|
if fail_job
|
193
213
|
message = "#{failed_count} slices failed to process"
|
@@ -199,7 +219,7 @@ module RocketJob
|
|
199
219
|
end
|
200
220
|
|
201
221
|
# Any work left?
|
202
|
-
return false if input_count
|
222
|
+
return false if input_count.positive?
|
203
223
|
|
204
224
|
# If the job was not saved to the queue, do not save any changes
|
205
225
|
if new_record?
|
@@ -212,12 +232,12 @@ module RocketJob
|
|
212
232
|
result = self.class.with(write: {w: 1}) do |query|
|
213
233
|
query.
|
214
234
|
where(id: id, state: :running, sub_state: :processing).
|
215
|
-
update(
|
235
|
+
update("$set" => {sub_state: :after, worker_name: worker_name})
|
216
236
|
end
|
217
237
|
|
218
238
|
# Reload to pull in any counters or other data that was modified.
|
219
239
|
reload
|
220
|
-
if result.modified_count
|
240
|
+
if result.modified_count.positive?
|
221
241
|
rocket_job_batch_run_after_callbacks(false)
|
222
242
|
else
|
223
243
|
# Repeat cleanup in case this worker was still running when the job was aborted
|
@@ -233,7 +253,7 @@ module RocketJob
|
|
233
253
|
self.sub_state = :before
|
234
254
|
save! unless new_record? || destroyed?
|
235
255
|
logger.measure_info(
|
236
|
-
|
256
|
+
"before_batch",
|
237
257
|
metric: "#{self.class.name}/before_batch",
|
238
258
|
log_exception: :full,
|
239
259
|
on_exception_level: :error,
|
@@ -253,7 +273,7 @@ module RocketJob
|
|
253
273
|
self.sub_state = :after
|
254
274
|
save! if save_before && !new_record? && !destroyed?
|
255
275
|
logger.measure_info(
|
256
|
-
|
276
|
+
"after_batch",
|
257
277
|
metric: "#{self.class.name}/after_batch",
|
258
278
|
log_exception: :full,
|
259
279
|
on_exception_level: :error,
|
@@ -269,20 +289,17 @@ module RocketJob
|
|
269
289
|
end
|
270
290
|
end
|
271
291
|
|
272
|
-
#
|
273
|
-
def
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
rocket_job_batch_run_after_callbacks
|
282
|
-
end
|
292
|
+
# Run Batch before and after callbacks
|
293
|
+
def rocket_job_batch_callbacks(worker)
|
294
|
+
# If this is the first worker to pickup this job
|
295
|
+
if sub_state == :before
|
296
|
+
rocket_job_batch_run_before_callbacks
|
297
|
+
# Check for 0 record jobs
|
298
|
+
rocket_job_batch_complete?(worker.name) if running?
|
299
|
+
elsif sub_state == :after
|
300
|
+
rocket_job_batch_run_after_callbacks
|
283
301
|
end
|
284
302
|
end
|
285
|
-
|
286
303
|
end
|
287
304
|
end
|
288
305
|
end
|