rocketjob 5.1.1 → 5.2.0.beta1
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/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
@@ -81,9 +81,10 @@ module RocketJob
|
|
81
81
|
|
82
82
|
begin
|
83
83
|
slice.save!
|
84
|
-
rescue Mongo::Error::OperationFailure =>
|
84
|
+
rescue Mongo::Error::OperationFailure => e
|
85
85
|
# Ignore duplicates since it means the job was restarted
|
86
|
-
raise(
|
86
|
+
raise(e) unless e.message.include?("E11000")
|
87
|
+
|
87
88
|
logger.warn "Skipped already processed slice# #{slice.id}"
|
88
89
|
end
|
89
90
|
slice
|
@@ -93,7 +94,7 @@ module RocketJob
|
|
93
94
|
|
94
95
|
# Index for find_and_modify only if it is not already present
|
95
96
|
def create_indexes
|
96
|
-
all.collection.indexes.create_one(state: 1, _id: 1) if all.collection.indexes.none? { |i| i[
|
97
|
+
all.collection.indexes.create_one(state: 1, _id: 1) if all.collection.indexes.none? { |i| i["name"] == "state_1__id_1" }
|
97
98
|
rescue Mongo::Error::OperationFailure
|
98
99
|
all.collection.indexes.create_one(state: 1, _id: 1)
|
99
100
|
end
|
@@ -124,13 +125,15 @@ module RocketJob
|
|
124
125
|
end
|
125
126
|
|
126
127
|
# Mongoid does not apply ordering, add sort
|
128
|
+
# rubocop:disable Style/RedundantSort
|
127
129
|
def first
|
128
|
-
all.sort(
|
130
|
+
all.sort("_id" => 1).first
|
129
131
|
end
|
130
132
|
|
131
133
|
def last
|
132
|
-
all.sort(
|
134
|
+
all.sort("_id" => -1).first
|
133
135
|
end
|
136
|
+
# rubocop:enable Style/RedundantSort
|
134
137
|
|
135
138
|
# Returns [Array<Struct>] grouped exceptions by class name,
|
136
139
|
# and unique exception messages by exception class.
|
@@ -149,19 +152,19 @@ module RocketJob
|
|
149
152
|
result = all.collection.aggregate(
|
150
153
|
[
|
151
154
|
{
|
152
|
-
|
155
|
+
"$match" => {state: "failed"}
|
153
156
|
},
|
154
157
|
{
|
155
|
-
|
156
|
-
_id: {error_class:
|
157
|
-
messages: {
|
158
|
-
count: {
|
158
|
+
"$group" => {
|
159
|
+
_id: {error_class: "$exception.class_name"},
|
160
|
+
messages: {"$addToSet" => "$exception.message"},
|
161
|
+
count: {"$sum" => 1}
|
159
162
|
}
|
160
163
|
}
|
161
164
|
]
|
162
165
|
)
|
163
166
|
result.collect do |errors|
|
164
|
-
result_struct.new(errors[
|
167
|
+
result_struct.new(errors["_id"]["error_class"], errors["count"], errors["messages"])
|
165
168
|
end
|
166
169
|
end
|
167
170
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_support/concern"
|
2
2
|
|
3
3
|
module RocketJob
|
4
4
|
# Mix-in to publish and subscribe to events.
|
@@ -66,12 +66,12 @@ module RocketJob
|
|
66
66
|
return
|
67
67
|
end
|
68
68
|
|
69
|
-
args =
|
69
|
+
args = method(action).arity.zero? || parameters.nil? ? nil : parameters.symbolize_keys
|
70
70
|
args ? public_send(action, **args) : public_send(action)
|
71
|
-
rescue ArgumentError =>
|
72
|
-
logger.error("##{action}: Invalid Arguments. Resuming..",
|
73
|
-
rescue StandardError =>
|
74
|
-
logger.error("##{action}: Exception caught. Resuming..",
|
71
|
+
rescue ArgumentError => e
|
72
|
+
logger.error("##{action}: Invalid Arguments. Resuming..", e)
|
73
|
+
rescue StandardError => e
|
74
|
+
logger.error("##{action}: Exception caught. Resuming..", e)
|
75
75
|
end
|
76
76
|
|
77
77
|
def process_event(name, action, parameters)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "socket"
|
2
2
|
|
3
3
|
module RocketJob
|
4
4
|
module Subscribers
|
@@ -9,8 +9,8 @@ module RocketJob
|
|
9
9
|
@host_name ||= Socket.gethostname
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
class << self
|
13
|
+
attr_writer :host_name
|
14
14
|
end
|
15
15
|
|
16
16
|
# Change the log level
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "rocket_job/supervisor/shutdown"
|
2
2
|
|
3
3
|
module RocketJob
|
4
4
|
# Starts a server instance, along with the workers and ensures workers remain running until they need to shutdown.
|
@@ -11,7 +11,7 @@ module RocketJob
|
|
11
11
|
|
12
12
|
# Start the Supervisor, using the supplied attributes to create a new Server instance.
|
13
13
|
def self.run
|
14
|
-
Thread.current.name =
|
14
|
+
Thread.current.name = "rocketjob main"
|
15
15
|
RocketJob.create_indexes
|
16
16
|
register_signal_handlers
|
17
17
|
|
@@ -29,9 +29,9 @@ module RocketJob
|
|
29
29
|
|
30
30
|
def run
|
31
31
|
logger.info "Using MongoDB Database: #{RocketJob::Job.collection.database.name}"
|
32
|
-
logger.info(
|
32
|
+
logger.info("Running with filter", Config.filter) if Config.filter
|
33
33
|
server.started!
|
34
|
-
logger.info
|
34
|
+
logger.info "Rocket Job Server started"
|
35
35
|
|
36
36
|
event_listener = Thread.new { Event.listener }
|
37
37
|
Subscribers::Server.subscribe(self) do
|
@@ -43,21 +43,21 @@ module RocketJob
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
rescue ::Mongoid::Errors::DocumentNotFound
|
46
|
-
logger.info(
|
47
|
-
rescue Exception =>
|
48
|
-
logger.error(
|
46
|
+
logger.info("Server has been destroyed. Going down hard!")
|
47
|
+
rescue Exception => e
|
48
|
+
logger.error("RocketJob::Server is stopping due to an exception", e)
|
49
49
|
ensure
|
50
|
-
event_listener
|
50
|
+
event_listener&.kill
|
51
51
|
# Logs the backtrace for each running worker
|
52
52
|
worker_pool.log_backtraces
|
53
|
-
logger.info(
|
53
|
+
logger.info("Shutdown Complete")
|
54
54
|
end
|
55
55
|
|
56
56
|
def stop!
|
57
57
|
server.stop! if server.may_stop?
|
58
58
|
worker_pool.stop
|
59
|
-
|
60
|
-
logger.info
|
59
|
+
until worker_pool.join
|
60
|
+
logger.info "Waiting for workers to finish processing ..."
|
61
61
|
# One or more workers still running so update heartbeat so that server reports "alive".
|
62
62
|
server.refresh(worker_pool.living_count)
|
63
63
|
end
|
@@ -65,7 +65,7 @@ module RocketJob
|
|
65
65
|
|
66
66
|
def supervise_pool
|
67
67
|
stagger = true
|
68
|
-
|
68
|
+
until self.class.shutdown?
|
69
69
|
synchronize do
|
70
70
|
if server.running?
|
71
71
|
worker_pool.prune
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "active_support/concern"
|
2
|
+
require "concurrent"
|
3
3
|
|
4
4
|
module RocketJob
|
5
5
|
class Supervisor
|
@@ -37,23 +37,23 @@ module RocketJob
|
|
37
37
|
# Perform clean shutdown
|
38
38
|
#
|
39
39
|
def self.register_signal_handlers
|
40
|
-
Signal.trap
|
40
|
+
Signal.trap "SIGTERM" do
|
41
41
|
Thread.new do
|
42
42
|
shutdown!
|
43
|
-
message =
|
43
|
+
message = "Shutdown signal (SIGTERM) received. Will shutdown as soon as active jobs/slices have completed."
|
44
44
|
logger.info(message)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
Signal.trap
|
48
|
+
Signal.trap "INT" do
|
49
49
|
Thread.new do
|
50
50
|
shutdown!
|
51
|
-
message =
|
51
|
+
message = "Shutdown signal (INT) received. Will shutdown as soon as active jobs/slices have completed."
|
52
52
|
logger.info(message)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
rescue StandardError
|
56
|
-
logger.warn
|
56
|
+
logger.warn "SIGTERM handler not installed. Not able to shutdown gracefully"
|
57
57
|
end
|
58
58
|
|
59
59
|
private_class_method :register_signal_handlers
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RocketJob
|
2
|
+
class ThrottleDefinition
|
3
|
+
attr_reader :method_name, :filter
|
4
|
+
|
5
|
+
def initialize(method_name, filter)
|
6
|
+
@method_name = method_name.to_sym
|
7
|
+
@filter = filter
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns [true|false] whether the throttle was triggered.
|
11
|
+
def throttled?(job, *args)
|
12
|
+
# Throttle exceeded?
|
13
|
+
# Throttle methods can be private.
|
14
|
+
throttled =
|
15
|
+
if args.size.positive?
|
16
|
+
job.method(method_name).arity.zero? ? job.send(method_name) : job.send(method_name, *args)
|
17
|
+
else
|
18
|
+
job.send(method_name)
|
19
|
+
end
|
20
|
+
return false unless throttled
|
21
|
+
|
22
|
+
job.logger.debug { "Throttle: #{method_name} has been exceeded." }
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the filter to apply to the job when the above throttle returns true.
|
27
|
+
def extract_filter(job, *args)
|
28
|
+
return filter.call(job, *args) if filter.is_a?(Proc)
|
29
|
+
|
30
|
+
if args.size.positive?
|
31
|
+
job.method(filter).arity.zero? ? job.send(filter) : job.send(filter, *args)
|
32
|
+
else
|
33
|
+
job.send(filter)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module RocketJob
|
2
|
+
class ThrottleDefinitions
|
3
|
+
attr_reader :throttles
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@throttles = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def add(method_name, filter)
|
10
|
+
unless filter.is_a?(Symbol) || filter.is_a?(Proc)
|
11
|
+
raise(ArgumentError, "Filter for #{method_name} must be a Symbol or Proc")
|
12
|
+
end
|
13
|
+
raise(ArgumentError, "Cannot define #{method_name} twice, undefine previous throttle first") if exist?(method_name)
|
14
|
+
|
15
|
+
@throttles += [ThrottleDefinition.new(method_name, filter)]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Undefine a previously defined throttle
|
19
|
+
def remove(method_name)
|
20
|
+
throttles.delete_if { |throttle| throttle.method_name == method_name }
|
21
|
+
end
|
22
|
+
|
23
|
+
# Has a throttle been defined?
|
24
|
+
def exist?(method_name)
|
25
|
+
throttles.any? { |throttle| throttle.method_name == method_name }
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the matching filter,
|
29
|
+
# or nil if no throttles were triggered.
|
30
|
+
def matching_filter(job, *args)
|
31
|
+
throttles.each do |throttle|
|
32
|
+
next unless throttle.throttled?(job, *args)
|
33
|
+
|
34
|
+
return throttle.extract_filter(job, *args)
|
35
|
+
end
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/rocket_job/version.rb
CHANGED
data/lib/rocket_job/worker.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "concurrent"
|
2
|
+
require "forwardable"
|
3
3
|
module RocketJob
|
4
4
|
# Worker
|
5
5
|
#
|
@@ -12,13 +12,13 @@ module RocketJob
|
|
12
12
|
define_callbacks :running
|
13
13
|
|
14
14
|
attr_accessor :id, :current_filter
|
15
|
-
attr_reader :thread, :name, :inline
|
15
|
+
attr_reader :thread, :name, :inline, :server_name
|
16
16
|
|
17
17
|
# Raised when a worker is killed so that it shutdown immediately, yet cleanly.
|
18
18
|
#
|
19
19
|
# Note:
|
20
20
|
# - It is not recommended to catch this exception since it is to shutdown workers quickly.
|
21
|
-
class Shutdown <
|
21
|
+
class Shutdown < RuntimeError
|
22
22
|
end
|
23
23
|
|
24
24
|
def self.before_running(*filters, &blk)
|
@@ -33,7 +33,7 @@ module RocketJob
|
|
33
33
|
set_callback(:running, :around, *filters, &blk)
|
34
34
|
end
|
35
35
|
|
36
|
-
def initialize(id: 0, server_name:
|
36
|
+
def initialize(id: 0, server_name: "inline:0", inline: false)
|
37
37
|
@id = id
|
38
38
|
@server_name = server_name
|
39
39
|
@shutdown = Concurrent::Event.new
|
@@ -76,49 +76,37 @@ module RocketJob
|
|
76
76
|
@shutdown.wait(timeout)
|
77
77
|
end
|
78
78
|
|
79
|
-
private
|
80
|
-
|
81
79
|
# Process jobs until it shuts down
|
82
80
|
#
|
83
81
|
# Params
|
84
82
|
# worker_id [Integer]
|
85
83
|
# The number of this worker for logging purposes
|
86
84
|
def run
|
87
|
-
Thread.current.name = format(
|
88
|
-
logger.info
|
89
|
-
until shutdown?
|
90
|
-
wait = Config.max_poll_seconds
|
91
|
-
if process_available_jobs
|
92
|
-
# Keeps workers staggered across the poll interval so that
|
93
|
-
# all workers don't poll at the same time
|
94
|
-
wait = rand(wait * 1000) / 1000
|
95
|
-
end
|
96
|
-
break if wait_for_shutdown?(wait)
|
97
|
-
end
|
98
|
-
logger.info 'Stopping'
|
99
|
-
rescue Exception => exc
|
100
|
-
logger.fatal('Unhandled exception in job processing thread', exc)
|
101
|
-
ensure
|
102
|
-
ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
|
103
|
-
end
|
85
|
+
Thread.current.name = format("rocketjob %03i", id)
|
86
|
+
logger.info "Started"
|
104
87
|
|
105
|
-
# Process the next available job
|
106
|
-
# Returns [Boolean] whether any job was actually processed
|
107
|
-
def process_available_jobs
|
108
|
-
processed = false
|
109
88
|
until shutdown?
|
89
|
+
sleep_seconds = Config.max_poll_seconds
|
110
90
|
reset_filter_if_expired
|
111
|
-
job =
|
112
|
-
break unless job
|
113
|
-
|
114
|
-
SemanticLogger.named_tagged(job: job.id.to_s) do
|
115
|
-
processed = true unless job.rocket_job_work(self, false, current_filter)
|
91
|
+
job = next_available_job
|
116
92
|
|
93
|
+
# Returns true when work was completed, but no other work is available
|
94
|
+
if job&.rocket_job_work(self, false)
|
117
95
|
# Return the database connections for this thread back to the connection pool
|
118
96
|
ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
|
97
|
+
|
98
|
+
# Stagger workers so that they don't all poll at the same time.
|
99
|
+
sleep_seconds = random_wait_interval
|
119
100
|
end
|
101
|
+
|
102
|
+
wait_for_shutdown?(sleep_seconds)
|
120
103
|
end
|
121
|
-
|
104
|
+
|
105
|
+
logger.info "Stopping"
|
106
|
+
rescue Exception => e
|
107
|
+
logger.fatal("Unhandled exception in job processing thread", e)
|
108
|
+
ensure
|
109
|
+
ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
|
122
110
|
end
|
123
111
|
|
124
112
|
# Resets the current job filter if the relevant time interval has passed
|
@@ -130,5 +118,99 @@ module RocketJob
|
|
130
118
|
@re_check_start = time
|
131
119
|
self.current_filter = Config.filter || {}
|
132
120
|
end
|
121
|
+
|
122
|
+
# Returns [RocketJob::Job] the next job available for processing.
|
123
|
+
# Returns [nil] if no job is available for processing.
|
124
|
+
#
|
125
|
+
# Notes:
|
126
|
+
# - Destroys expired jobs
|
127
|
+
# - Runs job throttles and skips the job if it is throttled.
|
128
|
+
# - Adding that filter to the current filter to exclude from subsequent polling.
|
129
|
+
def next_available_job
|
130
|
+
until shutdown?
|
131
|
+
job = find_and_assign_job
|
132
|
+
return unless job
|
133
|
+
|
134
|
+
if job.expired?
|
135
|
+
job.fail_on_exception! do
|
136
|
+
job.worker_name = name
|
137
|
+
job.destroy
|
138
|
+
logger.info("Destroyed expired job.")
|
139
|
+
end
|
140
|
+
next
|
141
|
+
end
|
142
|
+
|
143
|
+
# Batch Job that is already started?
|
144
|
+
# Batch has its own throttles for slices.
|
145
|
+
return job if job.running?
|
146
|
+
|
147
|
+
# Should this job be throttled?
|
148
|
+
next if job.fail_on_exception! { throttled_job?(job) }
|
149
|
+
|
150
|
+
# Start this job!
|
151
|
+
job.fail_on_exception! { job.start!(name) }
|
152
|
+
return job if job.running?
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Whether the supplied job has been throttled and should be ignored.
|
157
|
+
def throttled_job?(job)
|
158
|
+
# Evaluate job throttles, if any.
|
159
|
+
filter = job.rocket_job_throttles.matching_filter(job)
|
160
|
+
return false unless filter
|
161
|
+
|
162
|
+
add_to_current_filter(filter)
|
163
|
+
# Restore retrieved job so that other workers can process it later
|
164
|
+
job.set(worker_name: nil, state: :queued)
|
165
|
+
true
|
166
|
+
end
|
167
|
+
|
168
|
+
# Finds the next job to work on in priority based order
|
169
|
+
# and assigns it to this worker.
|
170
|
+
#
|
171
|
+
# Applies the current filter to exclude filtered jobs.
|
172
|
+
#
|
173
|
+
# Returns nil if no jobs are available for processing.
|
174
|
+
if Mongoid::VERSION.to_f >= 7.1
|
175
|
+
def find_and_assign_job
|
176
|
+
SemanticLogger.silence(:info) do
|
177
|
+
scheduled = RocketJob::Job.where(run_at: nil).or(:run_at.lte => Time.now)
|
178
|
+
working = RocketJob::Job.queued.or(state: :running, sub_state: :processing)
|
179
|
+
query = RocketJob::Job.and(working, scheduled)
|
180
|
+
query = query.and(current_filter) unless current_filter.blank?
|
181
|
+
update = {"$set" => {"worker_name" => name, "state" => "running"}}
|
182
|
+
query.sort(priority: 1, _id: 1).find_one_and_update(update, bypass_document_validation: true)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
else
|
186
|
+
def find_and_assign_job
|
187
|
+
SemanticLogger.silence(:info) do
|
188
|
+
scheduled = {"$or" => [{run_at: nil}, {:run_at.lte => Time.now}]}
|
189
|
+
working = {"$or" => [{state: :queued}, {state: :running, sub_state: :processing}]}
|
190
|
+
query = RocketJob::Job.and(working, scheduled)
|
191
|
+
query = query.where(current_filter) unless current_filter.blank?
|
192
|
+
update = {"$set" => {"worker_name" => name, "state" => "running"}}
|
193
|
+
query.sort(priority: 1, _id: 1).find_one_and_update(update, bypass_document_validation: true)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Add the supplied filter to the current filter.
|
199
|
+
def add_to_current_filter(filter)
|
200
|
+
filter.each_pair do |k, v|
|
201
|
+
current_filter[k] =
|
202
|
+
if (previous = current_filter[k])
|
203
|
+
v.is_a?(Array) ? previous + v : v
|
204
|
+
else
|
205
|
+
v
|
206
|
+
end
|
207
|
+
end
|
208
|
+
current_filter
|
209
|
+
end
|
210
|
+
|
211
|
+
# Returns [Float] a randomized poll interval in seconds up to the maximum configured poll interval.
|
212
|
+
def random_wait_interval
|
213
|
+
rand(Config.max_poll_seconds * 1000) / 1000
|
214
|
+
end
|
133
215
|
end
|
134
216
|
end
|