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
data/lib/rocket_job/cli.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
1
|
+
require "optparse"
|
2
|
+
require "json"
|
3
|
+
require "semantic_logger"
|
4
|
+
require "mongoid"
|
5
|
+
require "rocketjob"
|
6
|
+
require "pathname"
|
7
7
|
module RocketJob
|
8
8
|
# Command Line Interface parser for Rocket Job
|
9
9
|
class CLI
|
@@ -18,7 +18,7 @@ module RocketJob
|
|
18
18
|
@quiet = false
|
19
19
|
@environment = nil
|
20
20
|
@pidfile = nil
|
21
|
-
@directory =
|
21
|
+
@directory = "."
|
22
22
|
@log_level = nil
|
23
23
|
@log_file = nil
|
24
24
|
@mongo_config = nil
|
@@ -36,7 +36,7 @@ module RocketJob
|
|
36
36
|
|
37
37
|
# Run a RocketJob::Server from the command line
|
38
38
|
def run
|
39
|
-
Thread.current.name =
|
39
|
+
Thread.current.name = "rocketjob main"
|
40
40
|
RocketJob.server! if server
|
41
41
|
setup_environment
|
42
42
|
setup_logger
|
@@ -60,7 +60,7 @@ module RocketJob
|
|
60
60
|
def rails?
|
61
61
|
@rails ||=
|
62
62
|
begin
|
63
|
-
boot_file = Pathname.new(directory).join(
|
63
|
+
boot_file = Pathname.new(directory).join("config/environment.rb").expand_path
|
64
64
|
boot_file.file?
|
65
65
|
end
|
66
66
|
end
|
@@ -71,13 +71,13 @@ module RocketJob
|
|
71
71
|
logger.info "Loading Rails environment: #{environment}"
|
72
72
|
RocketJob.rails!
|
73
73
|
|
74
|
-
require
|
75
|
-
require
|
76
|
-
boot_file = Pathname.new(directory).join(
|
74
|
+
require "rails"
|
75
|
+
require "rocket_job/railtie"
|
76
|
+
boot_file = Pathname.new(directory).join("config/environment.rb").expand_path
|
77
77
|
require(boot_file.to_s)
|
78
78
|
|
79
79
|
begin
|
80
|
-
require
|
80
|
+
require "rails_semantic_logger"
|
81
81
|
rescue LoadError
|
82
82
|
raise "Add the following line to your Gemfile when running rails:\n gem 'rails_semantic_logger'"
|
83
83
|
end
|
@@ -87,10 +87,10 @@ module RocketJob
|
|
87
87
|
|
88
88
|
return unless Rails.configuration.eager_load
|
89
89
|
|
90
|
-
logger.measure_info(
|
90
|
+
logger.measure_info("Eager loaded Rails and all Engines") do
|
91
91
|
Rails.application.eager_load!
|
92
92
|
Rails::Engine.subclasses.each(&:eager_load!)
|
93
|
-
self.class.eager_load_jobs(File.expand_path(
|
93
|
+
self.class.eager_load_jobs(File.expand_path("jobs", File.dirname(__FILE__)))
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
@@ -98,13 +98,13 @@ module RocketJob
|
|
98
98
|
def boot_standalone
|
99
99
|
# Try to load bundler if present
|
100
100
|
begin
|
101
|
-
require
|
101
|
+
require "bundler/setup"
|
102
102
|
Bundler.require(environment)
|
103
103
|
rescue LoadError
|
104
104
|
nil
|
105
105
|
end
|
106
106
|
|
107
|
-
require
|
107
|
+
require "rocketjob"
|
108
108
|
|
109
109
|
# Log to file except when booting rails, when it will add the log file path
|
110
110
|
path = log_file ? Pathname.new(log_file) : Pathname.pwd.join("log/#{environment}.log")
|
@@ -113,7 +113,7 @@ module RocketJob
|
|
113
113
|
|
114
114
|
logger.info "Rails not detected. Running standalone: #{environment}"
|
115
115
|
RocketJob::Config.load!(environment, mongo_config, symmetric_encryption_config)
|
116
|
-
self.class.eager_load_jobs(File.expand_path(
|
116
|
+
self.class.eager_load_jobs(File.expand_path("jobs", File.dirname(__FILE__)))
|
117
117
|
self.class.eager_load_jobs
|
118
118
|
end
|
119
119
|
|
@@ -128,8 +128,9 @@ module RocketJob
|
|
128
128
|
# Create a PID file if requested
|
129
129
|
def write_pidfile
|
130
130
|
return unless pidfile
|
131
|
+
|
131
132
|
pid = $PID
|
132
|
-
File.open(pidfile,
|
133
|
+
File.open(pidfile, "w") { |f| f.puts(pid) }
|
133
134
|
|
134
135
|
# Remove pidfile on exit
|
135
136
|
at_exit do
|
@@ -140,9 +141,9 @@ module RocketJob
|
|
140
141
|
def setup_environment
|
141
142
|
# Override Env vars when environment is supplied
|
142
143
|
if environment
|
143
|
-
ENV[
|
144
|
+
ENV["RACK_ENV"] = ENV["RAILS_ENV"] = environment
|
144
145
|
else
|
145
|
-
self.environment = ENV[
|
146
|
+
self.environment = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
146
147
|
end
|
147
148
|
end
|
148
149
|
|
@@ -158,9 +159,10 @@ module RocketJob
|
|
158
159
|
end
|
159
160
|
|
160
161
|
# Eager load files in jobs folder
|
161
|
-
def self.eager_load_jobs(job_path =
|
162
|
+
def self.eager_load_jobs(job_path = "jobs")
|
162
163
|
Pathname.glob("#{job_path}/**/*.rb").each do |path|
|
163
164
|
next if path.directory?
|
165
|
+
|
164
166
|
logger.debug "Loading #{path}"
|
165
167
|
require path.expand_path.to_s
|
166
168
|
end
|
@@ -169,7 +171,7 @@ module RocketJob
|
|
169
171
|
def perform_list_servers(filter)
|
170
172
|
return list_the_servers(filter) unless refresh
|
171
173
|
|
172
|
-
|
174
|
+
loop do
|
173
175
|
list_the_servers(filter)
|
174
176
|
sleep(refresh)
|
175
177
|
puts
|
@@ -177,10 +179,10 @@ module RocketJob
|
|
177
179
|
end
|
178
180
|
|
179
181
|
def list_the_servers(filter)
|
180
|
-
|
181
|
-
puts format
|
182
|
+
layout = "%50.50s %20.20s %20.20s %20.20s %10.10s"
|
183
|
+
puts format(layout, "Server Name", "Workers(Current/Max)", "Started", "Heartbeat", "State")
|
182
184
|
header = "=" * 50
|
183
|
-
puts format
|
185
|
+
puts format(layout, header, header, header, header, header)
|
184
186
|
query = filter == :all ? RocketJob::Server.all : RocketJob::Server.where(name: /#{filter}/)
|
185
187
|
query.each do |server|
|
186
188
|
workers = "#{server&.heartbeat&.workers}/#{server.max_workers}"
|
@@ -188,14 +190,14 @@ module RocketJob
|
|
188
190
|
started = "#{RocketJob.seconds_as_duration(duration)} ago"
|
189
191
|
duration = Time.now - (server&.heartbeat&.updated_at || Time.now)
|
190
192
|
heartbeat = "#{RocketJob.seconds_as_duration(duration)} ago"
|
191
|
-
puts format
|
193
|
+
puts format(layout, server.name, workers, started, heartbeat, server.state)
|
192
194
|
end
|
193
195
|
0
|
194
196
|
end
|
195
197
|
|
196
198
|
def perform_server_action(server_name, action)
|
197
199
|
server_ids(server_name).each { |server_id| RocketJob::Subscribers::Server.publish(action, server_id: server_id) }
|
198
|
-
#RocketJob::Subscribers::Worker.publish(:stop, worker_id: 1, server_id: RocketJob::Server.running.last.id)
|
200
|
+
# RocketJob::Subscribers::Worker.publish(:stop, worker_id: 1, server_id: RocketJob::Server.running.last.id)
|
199
201
|
0
|
200
202
|
end
|
201
203
|
|
@@ -219,6 +221,7 @@ module RocketJob
|
|
219
221
|
if pid
|
220
222
|
server = RocketJob::Server.where(name: server_name).first
|
221
223
|
raise(ArgumentError, "No server with exact name: #{server_name} was found.") unless server
|
224
|
+
|
222
225
|
return [server.id]
|
223
226
|
end
|
224
227
|
|
@@ -230,90 +233,90 @@ module RocketJob
|
|
230
233
|
|
231
234
|
# Parse command line options placing results in the corresponding instance variables
|
232
235
|
def parse(argv)
|
233
|
-
parser
|
234
|
-
o.on(
|
236
|
+
parser = OptionParser.new do |o|
|
237
|
+
o.on("-n", "--name NAME", "Unique Name of this server (Default: host_name:PID)") do |arg|
|
235
238
|
Config.name = arg
|
236
239
|
end
|
237
|
-
o.on(
|
240
|
+
o.on("-w", "--workers COUNT", "Number of workers (threads) to start") do |arg|
|
238
241
|
@max_workers = arg.to_i
|
239
242
|
end
|
240
|
-
o.on(
|
243
|
+
o.on("--include REGEXP", 'Limit this server to only those job classes that match this regular expression (case-insensitive). Example: "DirmonJob|WeeklyReportJob"') do |arg|
|
241
244
|
@include_filter = Regexp.new(arg, true)
|
242
245
|
end
|
243
|
-
o.on(
|
244
|
-
warn
|
246
|
+
o.on("-F", "--filter REGEXP", "DEPRECATED. Use --include") do |arg|
|
247
|
+
warn "-F and --filter are deprecated, use --include"
|
245
248
|
@include_filter = Regexp.new(arg, true)
|
246
249
|
end
|
247
|
-
o.on(
|
250
|
+
o.on("-E", "--exclude REGEXP", 'Prevent this server from working on any job classes that match this regular expression (case-insensitive). Example: "DirmonJob|WeeklyReportJob"') do |arg|
|
248
251
|
@exclude_filter = Regexp.new(arg, true)
|
249
252
|
end
|
250
|
-
o.on(
|
253
|
+
o.on("-W", "--where JSON", "Limit this server instance to the supplied mongo query filter. Supply as a string in JSON format. Example: '{\"priority\":{\"$lte\":25}}'") do |arg|
|
251
254
|
@where_filter = JSON.parse(arg)
|
252
255
|
end
|
253
|
-
o.on(
|
256
|
+
o.on("-q", "--quiet", "Do not write to stdout, only to logfile. Necessary when running as a daemon") do
|
254
257
|
@quiet = true
|
255
258
|
end
|
256
|
-
o.on(
|
259
|
+
o.on("-d", "--dir DIR", "Directory containing Rails app, if not current directory") do |arg|
|
257
260
|
@directory = arg
|
258
261
|
end
|
259
|
-
o.on(
|
262
|
+
o.on("-e", "--environment ENVIRONMENT", "The environment to run the app on (Default: RAILS_ENV || RACK_ENV || development)") do |arg|
|
260
263
|
@environment = arg
|
261
264
|
end
|
262
|
-
o.on(
|
265
|
+
o.on("-l", "--log_level trace|debug|info|warn|error|fatal", "The log level to use") do |arg|
|
263
266
|
@log_level = arg
|
264
267
|
end
|
265
|
-
o.on(
|
268
|
+
o.on("-f", "--log_file FILE_NAME", "The log file to write to. Default: log/<environment>.log") do |arg|
|
266
269
|
@log_file = arg
|
267
270
|
end
|
268
|
-
o.on(
|
271
|
+
o.on("--pidfile PATH", "Use PATH as a pidfile") do |arg|
|
269
272
|
@pidfile = arg
|
270
273
|
end
|
271
|
-
o.on(
|
274
|
+
o.on("-m", "--mongo MONGO_CONFIG_FILE_NAME", "Path and filename of config file. Default: config/mongoid.yml") do |arg|
|
272
275
|
@mongo_config = arg
|
273
276
|
end
|
274
|
-
o.on(
|
277
|
+
o.on("-s", "--symmetric-encryption SYMMETRIC_ENCRYPTION_CONFIG_FILE_NAME", "Path and filename of Symmetric Encryption config file. Default: config/symmetric-encryption.yml") do |arg|
|
275
278
|
@symmetric_encryption_config = arg
|
276
279
|
end
|
277
|
-
o.on(
|
280
|
+
o.on("--list [FILTER]", "List active servers. Supply either an exact server name or a partial name as a filter.") do |filter|
|
278
281
|
@quiet = true
|
279
282
|
@server = false
|
280
283
|
@list_servers = filter || :all
|
281
284
|
end
|
282
|
-
o.on(
|
285
|
+
o.on("--refresh [SECONDS]", "When listing active servers, update the list by this number of seconds. Defaults to every 1 second.") do |seconds|
|
283
286
|
@refresh = (seconds || 1).to_s.to_f
|
284
287
|
end
|
285
|
-
o.on(
|
288
|
+
o.on("--stop [SERVER_NAME]", "Send event to stop a server once all in-process workers have completed. Optionally supply the complete or partial name of the server(s) to stop. Default: All servers.") do |server_name|
|
286
289
|
@quiet = true
|
287
290
|
@server = false
|
288
291
|
@stop_server = server_name || :all
|
289
292
|
end
|
290
|
-
o.on(
|
293
|
+
o.on("--kill [SERVER_NAME]", "Send event to hard kill a server. Optionally supply the complete or partial name of the server(s) to kill. Default: All servers.") do |server_name|
|
291
294
|
@quiet = true
|
292
295
|
@server = false
|
293
296
|
@kill_server = server_name || :all
|
294
297
|
end
|
295
|
-
o.on(
|
298
|
+
o.on("--pause [SERVER_NAME]", "Send event to pause a server. Optionally supply the complete or partial name of the server(s) to pause. Default: All servers.") do |server_name|
|
296
299
|
@quiet = true
|
297
300
|
@server = false
|
298
301
|
@pause_server = server_name || :all
|
299
302
|
end
|
300
|
-
o.on(
|
303
|
+
o.on("--resume [SERVER_NAME]", "Send event to resume a server. Optionally supply the complete or partial name of the server(s) to resume. Default: All servers.") do |server_name|
|
301
304
|
@quiet = true
|
302
305
|
@server = false
|
303
306
|
@resume_server = server_name || :all
|
304
307
|
end
|
305
|
-
o.on(
|
308
|
+
o.on("--dump [SERVER_NAME]", "Send event for a server to send a worker thread dump to its log file. Optionally supply the complete or partial name of the server(s). Default: All servers.") do |server_name|
|
306
309
|
@quiet = true
|
307
310
|
@server = false
|
308
311
|
@thread_dump = server_name || :all
|
309
312
|
end
|
310
|
-
o.on(
|
313
|
+
o.on("-v", "--version", "Print the version information") do
|
311
314
|
puts "Rocket Job v#{RocketJob::VERSION}"
|
312
315
|
exit 1
|
313
316
|
end
|
314
317
|
end
|
315
|
-
parser.banner =
|
316
|
-
parser.on_tail
|
318
|
+
parser.banner = "rocketjob <options>"
|
319
|
+
parser.on_tail "-h", "--help", "Show help" do
|
317
320
|
puts parser
|
318
321
|
exit 1
|
319
322
|
end
|
data/lib/rocket_job/config.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "yaml"
|
2
2
|
module RocketJob
|
3
3
|
# Rocket Job Configuration
|
4
4
|
class Config
|
@@ -72,8 +72,8 @@ module RocketJob
|
|
72
72
|
self.where_filter = nil
|
73
73
|
|
74
74
|
# Configure Mongoid
|
75
|
-
def self.load!(environment =
|
76
|
-
config_file = file_name ? Pathname.new(file_name) : Pathname.pwd.join(
|
75
|
+
def self.load!(environment = "development", file_name = nil, encryption_file_name = nil)
|
76
|
+
config_file = file_name ? Pathname.new(file_name) : Pathname.pwd.join("config/mongoid.yml")
|
77
77
|
|
78
78
|
raise(ArgumentError, "Mongo Configuration file: #{config_file} not found") unless config_file.file?
|
79
79
|
|
@@ -84,7 +84,7 @@ module RocketJob
|
|
84
84
|
if encryption_file_name
|
85
85
|
Pathname.new(encryption_file_name)
|
86
86
|
else
|
87
|
-
Pathname.pwd.join(
|
87
|
+
Pathname.pwd.join("config/symmetric-encryption.yml")
|
88
88
|
end
|
89
89
|
|
90
90
|
return unless config_file.file?
|
@@ -97,14 +97,12 @@ module RocketJob
|
|
97
97
|
# include_filter, exclude_filter, and where_filter.
|
98
98
|
# Returns nil if no filter should be applied.
|
99
99
|
def self.filter
|
100
|
-
if include_filter && exclude_filter
|
101
|
-
raise(ArgumentError, 'Cannot supply both an include_filter and an exclude_filter')
|
102
|
-
end
|
100
|
+
raise(ArgumentError, "Cannot supply both an include_filter and an exclude_filter") if include_filter && exclude_filter
|
103
101
|
|
104
102
|
filter = where_filter
|
105
|
-
(filter ||= {})[
|
106
|
-
(filter ||= {})[
|
107
|
-
filter
|
103
|
+
(filter ||= {})["_type"] = include_filter if include_filter
|
104
|
+
(filter ||= {})["_type"] = {"$not" => exclude_filter} if exclude_filter
|
105
|
+
filter&.dup
|
108
106
|
end
|
109
107
|
end
|
110
108
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "concurrent"
|
2
|
+
require "fileutils"
|
3
3
|
module RocketJob
|
4
4
|
class DirmonEntry
|
5
5
|
include Plugins::Document
|
@@ -8,9 +8,9 @@ module RocketJob
|
|
8
8
|
# The default archive directory that is used when the job being queued does not respond
|
9
9
|
# to #upload, and does not have an `archive_directory` specified in this entry
|
10
10
|
class_attribute :default_archive_directory
|
11
|
-
self.default_archive_directory =
|
11
|
+
self.default_archive_directory = "archive".freeze
|
12
12
|
|
13
|
-
store_in collection:
|
13
|
+
store_in collection: "rocket_job.dirmon_entries"
|
14
14
|
|
15
15
|
# User defined name used to identify this DirmonEntry in the Web Interface.
|
16
16
|
field :name, type: String
|
@@ -55,7 +55,7 @@ module RocketJob
|
|
55
55
|
field :archive_directory, type: String, default: default_archive_directory
|
56
56
|
|
57
57
|
# If this DirmonEntry is in the failed state, exception contains the cause
|
58
|
-
embeds_one :exception, class_name:
|
58
|
+
embeds_one :exception, class_name: "RocketJob::JobException"
|
59
59
|
|
60
60
|
# The maximum number of files that should ever match during a single poll of the pattern.
|
61
61
|
#
|
@@ -73,7 +73,7 @@ module RocketJob
|
|
73
73
|
field :state, type: Symbol, default: :pending
|
74
74
|
|
75
75
|
# Unique index on pattern to help prevent two entries from scanning the same files
|
76
|
-
index({pattern: 1}, background: true, unique: true
|
76
|
+
index({pattern: 1}, background: true, unique: true)
|
77
77
|
|
78
78
|
before_validation :strip_whitespace
|
79
79
|
validates_presence_of :pattern, :job_class_name, :archive_directory
|
@@ -175,8 +175,8 @@ module RocketJob
|
|
175
175
|
# # => {}
|
176
176
|
def self.counts_by_state
|
177
177
|
counts = {}
|
178
|
-
collection.aggregate([{
|
179
|
-
counts[result[
|
178
|
+
collection.aggregate([{"$group" => {_id: "$state", count: {"$sum" => 1}}}]).each do |result|
|
179
|
+
counts[result["_id"].to_sym] = result["count"]
|
180
180
|
end
|
181
181
|
counts
|
182
182
|
end
|
@@ -213,7 +213,7 @@ module RocketJob
|
|
213
213
|
exception.worker_name = worker_name
|
214
214
|
else
|
215
215
|
build_exception(
|
216
|
-
class_name:
|
216
|
+
class_name: "RocketJob::DirmonEntryException",
|
217
217
|
message: exc_or_message,
|
218
218
|
backtrace: [],
|
219
219
|
worker_name: worker_name
|
@@ -224,6 +224,7 @@ module RocketJob
|
|
224
224
|
# Returns the Job to be created.
|
225
225
|
def job_class
|
226
226
|
return if job_class_name.nil?
|
227
|
+
|
227
228
|
job_class_name.constantize
|
228
229
|
rescue NameError
|
229
230
|
nil
|
@@ -245,7 +246,7 @@ module RocketJob
|
|
245
246
|
)
|
246
247
|
|
247
248
|
logger.info(
|
248
|
-
message:
|
249
|
+
message: "Created RocketJob::Jobs::UploadFileJob",
|
249
250
|
payload: {
|
250
251
|
dirmon_entry_name: name,
|
251
252
|
upload_file_name: archive_path.to_s,
|
@@ -282,6 +283,7 @@ module RocketJob
|
|
282
283
|
def job_is_a_rocket_job
|
283
284
|
klass = job_class
|
284
285
|
return if job_class_name.nil? || klass&.ancestors&.include?(RocketJob::Job)
|
286
|
+
|
285
287
|
errors.add(:job_class_name, "Job #{job_class_name} must be defined and inherit from RocketJob::Job")
|
286
288
|
end
|
287
289
|
|
@@ -292,6 +294,7 @@ module RocketJob
|
|
292
294
|
|
293
295
|
properties.each_pair do |k, _v|
|
294
296
|
next if klass.public_method_defined?("#{k}=".to_sym)
|
297
|
+
|
295
298
|
errors.add(:properties, "Unknown Property: Attempted to set a value for #{k.inspect} which is not allowed on the job #{job_class_name}")
|
296
299
|
end
|
297
300
|
end
|
data/lib/rocket_job/event.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "concurrent-ruby"
|
2
2
|
|
3
3
|
module RocketJob
|
4
4
|
# RocketJob::Event
|
@@ -10,7 +10,7 @@ module RocketJob
|
|
10
10
|
include Plugins::Document
|
11
11
|
include Mongoid::Timestamps
|
12
12
|
|
13
|
-
ALL_EVENTS =
|
13
|
+
ALL_EVENTS = "*".freeze
|
14
14
|
|
15
15
|
# Capped collection long polling interval.
|
16
16
|
class_attribute :long_poll_seconds, instance_accessor: false
|
@@ -42,7 +42,7 @@ module RocketJob
|
|
42
42
|
|
43
43
|
validates_presence_of :name
|
44
44
|
|
45
|
-
store_in collection:
|
45
|
+
store_in collection: "rocket_job.events"
|
46
46
|
index({created_at: 1}, background: true)
|
47
47
|
|
48
48
|
# Add a subscriber for its events.
|
@@ -84,14 +84,14 @@ module RocketJob
|
|
84
84
|
# Indefinitely tail the capped collection looking for new events.
|
85
85
|
# time: the start time from which to start looking for new events.
|
86
86
|
def self.listener(time: @load_time)
|
87
|
-
Thread.current.name =
|
87
|
+
Thread.current.name = "rocketjob event"
|
88
88
|
create_capped_collection
|
89
89
|
|
90
|
-
logger.info(
|
90
|
+
logger.info("Event listener started")
|
91
91
|
tail_capped_collection(time) { |event| process_event(event) }
|
92
|
-
rescue Exception =>
|
93
|
-
logger.error(
|
94
|
-
raise(
|
92
|
+
rescue Exception => e
|
93
|
+
logger.error("#listener Event listener is terminating due to unhandled exception", e)
|
94
|
+
raise(e)
|
95
95
|
end
|
96
96
|
|
97
97
|
# Create the capped collection only if it does not exist.
|
@@ -117,13 +117,13 @@ module RocketJob
|
|
117
117
|
|
118
118
|
def self.tail_capped_collection(time)
|
119
119
|
with(socket_timeout: long_poll_seconds + 10) do
|
120
|
-
filter = {created_at: {
|
120
|
+
filter = {created_at: {"$gt" => time}}
|
121
121
|
collection.
|
122
122
|
find(filter).
|
123
123
|
await_data.
|
124
124
|
cursor_type(:tailable_await).
|
125
125
|
max_await_time_ms(long_poll_seconds * 1000).
|
126
|
-
sort(
|
126
|
+
sort("$natural" => 1).
|
127
127
|
each do |doc|
|
128
128
|
event = Mongoid::Factory.from_db(Event, doc)
|
129
129
|
# Recovery will occur from after the last message read
|
@@ -131,14 +131,14 @@ module RocketJob
|
|
131
131
|
yield(event)
|
132
132
|
end
|
133
133
|
end
|
134
|
-
rescue Mongo::Error::SocketError, Mongo::Error::SocketTimeoutError, Mongo::Error::OperationFailure, Timeout::Error =>
|
135
|
-
logger.info("Creating a new cursor and trying again: #{
|
134
|
+
rescue Mongo::Error::SocketError, Mongo::Error::SocketTimeoutError, Mongo::Error::OperationFailure, Timeout::Error => e
|
135
|
+
logger.info("Creating a new cursor and trying again: #{e.class.name} #{e.message}")
|
136
136
|
retry
|
137
137
|
end
|
138
138
|
|
139
139
|
# Process a new event, calling registered subscribers.
|
140
140
|
def self.process_event(event)
|
141
|
-
logger.info(
|
141
|
+
logger.info("Event Received", event.attributes)
|
142
142
|
|
143
143
|
if @subscribers.key?(event.name)
|
144
144
|
@subscribers[event.name].each { |subscriber| subscriber.process_action(event.action, event.parameters) }
|
@@ -147,8 +147,8 @@ module RocketJob
|
|
147
147
|
if @subscribers.key?(ALL_EVENTS)
|
148
148
|
@subscribers[ALL_EVENTS].each { |subscriber| subscriber.process_event(event.name, event.action, event.parameters) }
|
149
149
|
end
|
150
|
-
rescue StandardError =>
|
151
|
-
logger.error(
|
150
|
+
rescue StandardError => e
|
151
|
+
logger.error("Unknown subscriber. Continuing..", e)
|
152
152
|
end
|
153
153
|
|
154
154
|
def self.collection_exists?
|
@@ -157,7 +157,7 @@ module RocketJob
|
|
157
157
|
|
158
158
|
# Convert a non-capped collection to capped
|
159
159
|
def self.convert_to_capped_collection(size)
|
160
|
-
collection.database.command(
|
160
|
+
collection.database.command("convertToCapped" => collection_name.to_s, "size" => size)
|
161
161
|
end
|
162
162
|
end
|
163
163
|
end
|