rocketjob 3.4.3 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +27 -0
- data/bin/rocketjob +1 -1
- data/lib/rocket_job/active_worker.rb +4 -3
- data/lib/rocket_job/cli.rb +13 -12
- data/lib/rocket_job/config.rb +17 -13
- data/lib/rocket_job/dirmon_entry.rb +88 -91
- data/lib/rocket_job/extensions/mongo/logging.rb +8 -4
- data/lib/rocket_job/extensions/mongoid/factory.rb +8 -6
- data/lib/rocket_job/extensions/rocket_job_adapter.rb +2 -4
- data/lib/rocket_job/heartbeat.rb +7 -8
- data/lib/rocket_job/job_exception.rb +6 -5
- data/lib/rocket_job/jobs/dirmon_job.rb +5 -7
- data/lib/rocket_job/jobs/housekeeping_job.rb +3 -2
- data/lib/rocket_job/jobs/on_demand_job.rb +104 -0
- data/lib/rocket_job/jobs/simple_job.rb +0 -2
- data/lib/rocket_job/jobs/upload_file_job.rb +100 -0
- data/lib/rocket_job/performance.rb +15 -10
- data/lib/rocket_job/plugins/cron.rb +7 -124
- data/lib/rocket_job/plugins/document.rb +8 -10
- data/lib/rocket_job/plugins/job/callbacks.rb +0 -1
- data/lib/rocket_job/plugins/job/logger.rb +0 -1
- data/lib/rocket_job/plugins/job/model.rb +15 -20
- data/lib/rocket_job/plugins/job/persistence.rb +3 -13
- data/lib/rocket_job/plugins/job/state_machine.rb +1 -2
- data/lib/rocket_job/plugins/job/throttle.rb +16 -12
- data/lib/rocket_job/plugins/job/worker.rb +15 -19
- data/lib/rocket_job/plugins/processing_window.rb +2 -2
- data/lib/rocket_job/plugins/restart.rb +3 -4
- data/lib/rocket_job/plugins/retry.rb +2 -3
- data/lib/rocket_job/plugins/singleton.rb +2 -3
- data/lib/rocket_job/plugins/state_machine.rb +19 -23
- data/lib/rocket_job/rocket_job.rb +4 -5
- data/lib/rocket_job/server.rb +35 -41
- data/lib/rocket_job/version.rb +2 -2
- data/lib/rocket_job/worker.rb +22 -21
- data/lib/rocketjob.rb +2 -0
- data/test/config/mongoid.yml +2 -2
- data/test/config_test.rb +0 -2
- data/test/dirmon_entry_test.rb +161 -134
- data/test/dirmon_job_test.rb +80 -78
- data/test/job_test.rb +0 -2
- data/test/jobs/housekeeping_job_test.rb +0 -1
- data/test/jobs/on_demand_job_test.rb +59 -0
- data/test/jobs/upload_file_job_test.rb +99 -0
- data/test/plugins/cron_test.rb +1 -3
- data/test/plugins/job/callbacks_test.rb +8 -13
- data/test/plugins/job/defaults_test.rb +0 -1
- data/test/plugins/job/logger_test.rb +2 -4
- data/test/plugins/job/model_test.rb +1 -2
- data/test/plugins/job/persistence_test.rb +0 -2
- data/test/plugins/job/state_machine_test.rb +0 -2
- data/test/plugins/job/throttle_test.rb +6 -8
- data/test/plugins/job/worker_test.rb +1 -2
- data/test/plugins/processing_window_test.rb +0 -2
- data/test/plugins/restart_test.rb +0 -1
- data/test/plugins/retry_test.rb +1 -2
- data/test/plugins/singleton_test.rb +0 -2
- data/test/plugins/state_machine_event_callbacks_test.rb +1 -2
- data/test/plugins/state_machine_test.rb +0 -2
- data/test/plugins/transaction_test.rb +5 -7
- data/test/test_db.sqlite3 +0 -0
- data/test/test_helper.rb +2 -1
- metadata +42 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9dd8c3c0ab00ae83d73d63aef3887f62d1d2a695399f263814ad7a5881aa980a
|
4
|
+
data.tar.gz: 715304e4587a9eda64c3cb5f73a69cd72ecdbf4ee232884c61f36666ef7c1a3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bc50f4e10068d2b193747c24880dee618be8df6ab58e3093f442332f93c591796901132490a856ee955aa19cb78abaad6034eb7280e080c494676c7c36d3899
|
7
|
+
data.tar.gz: 86d8dbe971e8e44a8e4854d1691078ac93a25f84fd8e482b9e84a3669457ad8886f84fc47007f199625e70fcecc1f4b1403804e38dc50acebd5c06b13b11d20b
|
data/README.md
CHANGED
@@ -17,6 +17,33 @@ Checkout http://rocketjob.io/
|
|
17
17
|
* Questions? Join the chat room on Gitter for [rocketjob support](https://gitter.im/rocketjob/support)
|
18
18
|
* [Report bugs](https://github.com/rocketjob/rocketjob/issues)
|
19
19
|
|
20
|
+
## Contributing to the documentation
|
21
|
+
|
22
|
+
To contribute to the documentation it is as easy as forking the repository
|
23
|
+
and then editing the markdown pages directly via the github web interface.
|
24
|
+
|
25
|
+
For more complex documentation changes checkout the source code locally.
|
26
|
+
|
27
|
+
#### Local checkout
|
28
|
+
|
29
|
+
* Fork the repository in github.
|
30
|
+
* Checkout your fork of the source code locally.
|
31
|
+
* Install Jekyll
|
32
|
+
~~~
|
33
|
+
cd docs
|
34
|
+
bundle update
|
35
|
+
~~~
|
36
|
+
* Run Jekyll web server:
|
37
|
+
~~~
|
38
|
+
jekyll serve
|
39
|
+
~~~
|
40
|
+
* Open a web browser to view the local documentation:
|
41
|
+
[http://127.0.0.1:4000](http://127.0.0.1:4000)
|
42
|
+
* Edit the files in the `/docs` folder.
|
43
|
+
* Refresh the page to see the changes.
|
44
|
+
|
45
|
+
Once the changes are complete, submit a github pull request.
|
46
|
+
|
20
47
|
## Upgrading to V3
|
21
48
|
|
22
49
|
V3 replaces MongoMapper with Mongoid which supports the latest MongoDB Ruby client driver.
|
data/bin/rocketjob
CHANGED
@@ -6,7 +6,7 @@ require 'rocket_job/cli'
|
|
6
6
|
# Start a rocketjob server instance from the command line
|
7
7
|
begin
|
8
8
|
RocketJob::CLI.new(ARGV).run
|
9
|
-
rescue => exc
|
9
|
+
rescue Exception => exc
|
10
10
|
# Failsafe logger that writes to STDERR
|
11
11
|
SemanticLogger.add_appender(io: STDERR, level: :error, formatter: :color)
|
12
12
|
SemanticLogger['RocketJob'].error('Rocket Job shutting down due to exception', exc)
|
@@ -4,7 +4,8 @@ module RocketJob
|
|
4
4
|
# When this server started working on this job / slice
|
5
5
|
attr_accessor :started_at
|
6
6
|
|
7
|
-
attr_accessor :
|
7
|
+
attr_accessor :job
|
8
|
+
attr_reader :name
|
8
9
|
|
9
10
|
# Returns [Hash<String:ActiveWorker>] hash of all servers sorted by name
|
10
11
|
# and what they are currently working on.
|
@@ -16,7 +17,7 @@ module RocketJob
|
|
16
17
|
def self.all(server_name = nil)
|
17
18
|
servers = []
|
18
19
|
# Need paused, failed or aborted since servers may still be working on active slices
|
19
|
-
query = RocketJob::Job.where(:state.in => [
|
20
|
+
query = RocketJob::Job.where(:state.in => %i[running paused failed aborted])
|
20
21
|
query = query.where(worker_name: /\A#{server_name}/) if server_name
|
21
22
|
query.each do |job|
|
22
23
|
servers += job.rocket_job_active_workers
|
@@ -50,7 +51,7 @@ module RocketJob
|
|
50
51
|
|
51
52
|
# Returns [String] the name of the server running this worker
|
52
53
|
def server_name
|
53
|
-
if match = name.to_s.match(/(.*:.*):.*/)
|
54
|
+
if (match = name.to_s.match(/(.*:.*):.*/))
|
54
55
|
match[1]
|
55
56
|
else
|
56
57
|
name
|
data/lib/rocket_job/cli.rb
CHANGED
@@ -4,7 +4,7 @@ require 'mongoid'
|
|
4
4
|
require 'rocketjob'
|
5
5
|
require 'rocket_job/extensions/mongoid/factory'
|
6
6
|
module RocketJob
|
7
|
-
# Command Line Interface parser for
|
7
|
+
# Command Line Interface parser for Rocket Job
|
8
8
|
class CLI
|
9
9
|
include SemanticLogger::Loggable
|
10
10
|
attr_accessor :name, :workers, :environment, :pidfile, :directory, :quiet,
|
@@ -41,7 +41,7 @@ module RocketJob
|
|
41
41
|
opts = {}
|
42
42
|
opts[:name] = name if name
|
43
43
|
opts[:max_workers] = workers if workers
|
44
|
-
opts[:filter] = {:
|
44
|
+
opts[:filter] = {_type: filter} if filter
|
45
45
|
Server.run(opts)
|
46
46
|
end
|
47
47
|
|
@@ -70,12 +70,12 @@ module RocketJob
|
|
70
70
|
# Override Rails log level if command line option was supplied
|
71
71
|
SemanticLogger.default_level = log_level.to_sym if log_level
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
return unless Rails.configuration.eager_load
|
74
|
+
|
75
|
+
logger.measure_info('Eager loaded Rails and all Engines') do
|
76
|
+
Rails.application.eager_load!
|
77
|
+
Rails::Engine.subclasses.each(&:eager_load!)
|
78
|
+
self.class.eager_load_jobs(File.expand_path('jobs', File.dirname(__FILE__)))
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
@@ -86,12 +86,14 @@ module RocketJob
|
|
86
86
|
require 'bundler/setup'
|
87
87
|
Bundler.require(environment)
|
88
88
|
rescue LoadError
|
89
|
+
nil
|
89
90
|
end
|
90
91
|
|
91
92
|
require 'rocketjob'
|
92
93
|
begin
|
93
94
|
require 'rocketjob_pro'
|
94
95
|
rescue LoadError
|
96
|
+
nil
|
95
97
|
end
|
96
98
|
|
97
99
|
# Log to file except when booting rails, when it will add the log file path
|
@@ -138,10 +140,10 @@ module RocketJob
|
|
138
140
|
end
|
139
141
|
|
140
142
|
# Eager load files in jobs folder
|
141
|
-
def self.eager_load_jobs(
|
142
|
-
Pathname.glob("#{
|
143
|
+
def self.eager_load_jobs(job_path = 'jobs')
|
144
|
+
Pathname.glob("#{job_path}/**/*.rb").each do |path|
|
143
145
|
next if path.directory?
|
144
|
-
logger.debug "Loading #{path
|
146
|
+
logger.debug "Loading #{path}"
|
145
147
|
require path.expand_path.to_s
|
146
148
|
end
|
147
149
|
end
|
@@ -198,6 +200,5 @@ module RocketJob
|
|
198
200
|
end
|
199
201
|
parser.parse! argv
|
200
202
|
end
|
201
|
-
|
202
203
|
end
|
203
204
|
end
|
data/lib/rocket_job/config.rb
CHANGED
@@ -51,22 +51,26 @@ module RocketJob
|
|
51
51
|
# Configure Mongoid
|
52
52
|
def self.load!(environment = 'development', file_name = nil, encryption_file_name = nil)
|
53
53
|
config_file = file_name ? Pathname.new(file_name) : Pathname.pwd.join('config/mongoid.yml')
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
54
|
+
|
55
|
+
raise(ArgumentError, "Mongo Configuration file: #{config_file} not found") unless config_file.file?
|
56
|
+
|
57
|
+
logger.debug "Reading Mongo configuration from: #{config_file}"
|
58
|
+
Mongoid.load!(config_file, environment)
|
60
59
|
|
61
60
|
# Load Encryption configuration file if present
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
return unless defined?(SymmetricEncryption)
|
62
|
+
|
63
|
+
config_file =
|
64
|
+
if encryption_file_name
|
65
|
+
Pathname.new(encryption_file_name)
|
66
|
+
else
|
67
|
+
Pathname.pwd.join('config/symmetric-encryption.yml')
|
67
68
|
end
|
68
|
-
end
|
69
|
-
end
|
70
69
|
|
70
|
+
return unless config_file.file?
|
71
|
+
|
72
|
+
logger.debug "Reading SymmetricEncryption configuration from: #{config_file}"
|
73
|
+
SymmetricEncryption.load!(config_file.to_s, environment)
|
74
|
+
end
|
71
75
|
end
|
72
76
|
end
|
@@ -6,9 +6,14 @@ module RocketJob
|
|
6
6
|
include Plugins::Document
|
7
7
|
include Plugins::StateMachine
|
8
8
|
|
9
|
+
# The default archive directory that is used when the job being queued does not respond
|
10
|
+
# to #upload, and does not have an `archive_directory` specified in this entry
|
11
|
+
class_attribute :default_archive_directory
|
12
|
+
self.default_archive_directory = 'archive'.freeze
|
13
|
+
|
9
14
|
store_in collection: 'rocket_job.dirmon_entries'
|
10
15
|
|
11
|
-
# User defined name used to identify this DirmonEntry in
|
16
|
+
# User defined name used to identify this DirmonEntry in the Web Interface.
|
12
17
|
field :name, type: String
|
13
18
|
|
14
19
|
# Pattern for finding files
|
@@ -48,7 +53,7 @@ module RocketJob
|
|
48
53
|
# If supplied, the file will be moved to this directory before the job is started
|
49
54
|
# If the file was in a sub-directory, the corresponding sub-directory will
|
50
55
|
# be created in the archive directory.
|
51
|
-
field :archive_directory, type: String
|
56
|
+
field :archive_directory, type: String, default: default_archive_directory
|
52
57
|
|
53
58
|
# If this DirmonEntry is in the failed state, exception contains the cause
|
54
59
|
embeds_one :exception, class_name: 'RocketJob::JobException'
|
@@ -59,7 +64,7 @@ module RocketJob
|
|
59
64
|
# Exceeding this number will result in an exception being logged in a failed Dirmon instance.
|
60
65
|
# Dirmon processing will continue with new instances.
|
61
66
|
# TODO: Implement max_hits
|
62
|
-
#field :max_hits, type: Integer, default: 100
|
67
|
+
# field :max_hits, type: Integer, default: 100
|
63
68
|
|
64
69
|
#
|
65
70
|
# Read-only attributes
|
@@ -71,6 +76,11 @@ module RocketJob
|
|
71
76
|
# Unique index on pattern to help prevent two entries from scanning the same files
|
72
77
|
index({pattern: 1}, background: true, unique: true, drop_dups: true)
|
73
78
|
|
79
|
+
before_validation :strip_whitespace
|
80
|
+
validates_presence_of :pattern, :job_class_name, :archive_directory
|
81
|
+
validate :job_is_a_rocket_job
|
82
|
+
validate :job_has_properties
|
83
|
+
|
74
84
|
# State Machine events and transitions
|
75
85
|
#
|
76
86
|
# :pending -> :enabled -> :disabled
|
@@ -108,27 +118,6 @@ module RocketJob
|
|
108
118
|
end
|
109
119
|
end
|
110
120
|
|
111
|
-
# @formatter:on
|
112
|
-
validates_presence_of :pattern, :job_class_name
|
113
|
-
|
114
|
-
validates_each :job_class_name do |record, attr, value|
|
115
|
-
exists =
|
116
|
-
begin
|
117
|
-
value.nil? ? false : record.job_class.ancestors.include?(RocketJob::Job)
|
118
|
-
rescue NameError
|
119
|
-
false
|
120
|
-
end
|
121
|
-
record.errors.add(attr, 'job_class_name must be defined and must be derived from RocketJob::Job') unless exists
|
122
|
-
end
|
123
|
-
|
124
|
-
validates_each :properties do |record, attr, value|
|
125
|
-
if record.job_class && (methods = record.job_class.instance_methods)
|
126
|
-
value.each_pair do |k, v|
|
127
|
-
record.errors.add(attr, "Unknown property: #{k.inspect} with value: #{v}") unless methods.include?("#{k}=".to_sym)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
121
|
# Security Settings
|
133
122
|
#
|
134
123
|
# A whitelist of paths from which to process files.
|
@@ -147,7 +136,7 @@ module RocketJob
|
|
147
136
|
#
|
148
137
|
# Returns [Array<String>] a copy of the whitelisted paths
|
149
138
|
def self.get_whitelist_paths
|
150
|
-
|
139
|
+
whitelist_paths.dup
|
151
140
|
end
|
152
141
|
|
153
142
|
# Add a path to the whitelist
|
@@ -155,8 +144,8 @@ module RocketJob
|
|
155
144
|
def self.add_whitelist_path(path)
|
156
145
|
# Confirms that path exists
|
157
146
|
path = Pathname.new(path).realpath.to_s
|
158
|
-
|
159
|
-
|
147
|
+
whitelist_paths << path
|
148
|
+
whitelist_paths.uniq!
|
160
149
|
path
|
161
150
|
end
|
162
151
|
|
@@ -165,8 +154,8 @@ module RocketJob
|
|
165
154
|
def self.delete_whitelist_path(path)
|
166
155
|
# Confirms that path exists
|
167
156
|
path = Pathname.new(path).realpath.to_s
|
168
|
-
|
169
|
-
|
157
|
+
whitelist_paths.delete(path)
|
158
|
+
whitelist_paths.uniq!
|
170
159
|
path
|
171
160
|
end
|
172
161
|
|
@@ -193,30 +182,8 @@ module RocketJob
|
|
193
182
|
counts
|
194
183
|
end
|
195
184
|
|
196
|
-
# The default archive directory that is used when the job being queued does not respond
|
197
|
-
# to #upload, and does not have an `archive_directory` specified in this entry
|
198
|
-
class_attribute :default_archive_directory
|
199
|
-
|
200
|
-
self.default_archive_directory = '_archive'.freeze
|
201
|
-
|
202
|
-
# Returns [Pathname] the archive_directory if set, otherwise the default_archive_directory
|
203
|
-
# Creates the archive directory if one is set
|
204
|
-
def archive_pathname(file_pathname)
|
205
|
-
if archive_directory
|
206
|
-
path = Pathname.new(archive_directory)
|
207
|
-
begin
|
208
|
-
path.mkpath unless path.exist?
|
209
|
-
rescue Errno::ENOENT => exc
|
210
|
-
raise(Errno::ENOENT, "DirmonJob failed to create archive directory: #{path}, #{exc.message}")
|
211
|
-
end
|
212
|
-
path.realpath
|
213
|
-
else
|
214
|
-
file_pathname.dirname.join(self.class.default_archive_directory).realdirpath
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
185
|
# Passes each filename [Pathname] found that matches the pattern into the supplied block
|
219
|
-
def each
|
186
|
+
def each
|
220
187
|
SemanticLogger.named_tagged(dirmon_entry: id.to_s) do
|
221
188
|
# Case insensitive filename matching
|
222
189
|
Pathname.glob(pattern, File::FNM_CASEFOLD).each do |pathname|
|
@@ -234,7 +201,7 @@ module RocketJob
|
|
234
201
|
next if file_name.include?(self.class.default_archive_directory)
|
235
202
|
|
236
203
|
# Security check?
|
237
|
-
if
|
204
|
+
if whitelist_paths.size.positive? && whitelist_paths.none? { |whitepath| file_name.to_s.start_with?(whitepath) }
|
238
205
|
logger.error "Skipping file: #{file_name} since it is not in any of the whitelisted paths: #{whitelist_paths.join(', ')}"
|
239
206
|
next
|
240
207
|
end
|
@@ -244,7 +211,7 @@ module RocketJob
|
|
244
211
|
logger.error "Skipping file: #{file_name} since it is not writable by the current user. Must be able to delete/move the file after queueing the job"
|
245
212
|
next
|
246
213
|
end
|
247
|
-
|
214
|
+
yield(pathname)
|
248
215
|
end
|
249
216
|
end
|
250
217
|
end
|
@@ -264,7 +231,7 @@ module RocketJob
|
|
264
231
|
end
|
265
232
|
end
|
266
233
|
|
267
|
-
# Returns the Job to be
|
234
|
+
# Returns the Job to be created.
|
268
235
|
def job_class
|
269
236
|
return if job_class_name.nil?
|
270
237
|
job_class_name.constantize
|
@@ -272,47 +239,44 @@ module RocketJob
|
|
272
239
|
nil
|
273
240
|
end
|
274
241
|
|
275
|
-
#
|
242
|
+
# Archives the file and kicks off a proxy job to upload the file.
|
276
243
|
def later(pathname)
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
244
|
+
job_id = BSON::ObjectId.new
|
245
|
+
archived_file_name = archive_file(job_id, pathname)
|
246
|
+
|
247
|
+
job = RocketJob::Jobs::UploadFileJob.create!(
|
248
|
+
job_class_name: job_class_name,
|
249
|
+
properties: properties,
|
250
|
+
description: "#{name}: #{pathname.basename}",
|
251
|
+
upload_file_name: archived_file_name.to_s,
|
252
|
+
original_file_name: pathname.to_s,
|
253
|
+
job_id: job_id
|
254
|
+
)
|
255
|
+
|
256
|
+
logger.info(
|
257
|
+
message: 'Created RocketJob::Jobs::UploadFileJob',
|
258
|
+
payload: {
|
259
|
+
dirmon_entry_name: name,
|
260
|
+
upload_file_name: archived_file_name.to_s,
|
261
|
+
original_file_name: pathname.to_s,
|
262
|
+
job_class_name: job_class_name,
|
263
|
+
job_id: job_id.to_s,
|
264
|
+
upload_job_id: job.id.to_s
|
265
|
+
}
|
266
|
+
)
|
267
|
+
job
|
287
268
|
end
|
288
269
|
|
289
270
|
private
|
290
271
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
def upload_file(job, pathname)
|
296
|
-
if job.respond_to?(:upload)
|
297
|
-
# With RocketJob Pro the file can be uploaded directly into the Job itself
|
298
|
-
job.upload(pathname.to_s)
|
299
|
-
archive_directory ? archive_file(job, pathname) : pathname.unlink
|
300
|
-
else
|
301
|
-
upload_default(job, pathname)
|
302
|
-
end
|
272
|
+
# strip whitespaces from all variables that reference paths or patterns
|
273
|
+
def strip_whitespace
|
274
|
+
self.pattern = pattern.strip unless pattern.nil?
|
275
|
+
self.archive_directory = archive_directory.strip unless archive_directory.nil?
|
303
276
|
end
|
304
277
|
|
305
|
-
|
306
|
-
|
307
|
-
full_file_name = archive_file(job, pathname)
|
308
|
-
if job.respond_to?(:upload_file_name=)
|
309
|
-
job.upload_file_name = full_file_name
|
310
|
-
elsif job.respond_to?(:full_file_name=)
|
311
|
-
job.full_file_name = full_file_name
|
312
|
-
else
|
313
|
-
raise(ArgumentError, "#{job_class_name} must either have attribute 'upload_file_name' or 'full_file_name'")
|
314
|
-
end
|
315
|
-
end
|
278
|
+
class_attribute :whitelist_paths
|
279
|
+
self.whitelist_paths = Concurrent::Array.new
|
316
280
|
|
317
281
|
# Move the file to the archive directory
|
318
282
|
#
|
@@ -322,14 +286,47 @@ module RocketJob
|
|
322
286
|
#
|
323
287
|
# Note:
|
324
288
|
# - Works across partitions when the file and the archive are on different partitions
|
325
|
-
def archive_file(
|
289
|
+
def archive_file(job_id, pathname)
|
326
290
|
target_path = archive_pathname(pathname)
|
327
291
|
target_path.mkpath
|
328
|
-
target_file_name = target_path.join("#{
|
292
|
+
target_file_name = target_path.join("#{job_id}_#{pathname.basename}")
|
329
293
|
# In case the file is being moved across partitions
|
330
294
|
FileUtils.move(pathname.to_s, target_file_name.to_s)
|
331
295
|
target_file_name.to_s
|
332
296
|
end
|
333
297
|
|
298
|
+
# Returns [Pathname] to the archive directory, and creates it if it does not exist.
|
299
|
+
#
|
300
|
+
# If `archive_directory` is a relative path, it is appended to the `file_pathname`.
|
301
|
+
# If `archive_directory` is an absolute path, it is returned as-is.
|
302
|
+
def archive_pathname(file_pathname)
|
303
|
+
path = Pathname.new(archive_directory)
|
304
|
+
path = file_pathname.dirname.join(archive_directory) if path.relative?
|
305
|
+
|
306
|
+
begin
|
307
|
+
path.mkpath unless path.exist?
|
308
|
+
rescue Errno::ENOENT => exc
|
309
|
+
raise(Errno::ENOENT, "DirmonJob failed to create archive directory: #{path}, #{exc.message}")
|
310
|
+
end
|
311
|
+
path.realpath
|
312
|
+
end
|
313
|
+
|
314
|
+
# Validates job_class is a Rocket Job
|
315
|
+
def job_is_a_rocket_job
|
316
|
+
klass = job_class
|
317
|
+
return if job_class_name.nil? || klass&.ancestors&.include?(RocketJob::Job)
|
318
|
+
errors.add(:job_class_name, "Job #{job_class_name} must be defined and inherit from RocketJob::Job")
|
319
|
+
end
|
320
|
+
|
321
|
+
# Does the job have all the supplied properties
|
322
|
+
def job_has_properties
|
323
|
+
klass = job_class
|
324
|
+
return unless klass
|
325
|
+
|
326
|
+
properties.each_pair do |k, _v|
|
327
|
+
next if klass.public_method_defined?("#{k}=".to_sym)
|
328
|
+
errors.add(:properties, "Unknown Property: Attempted to set a value for #{k.inspect} which is not allowed on the job #{job_class_name}")
|
329
|
+
end
|
330
|
+
end
|
334
331
|
end
|
335
332
|
end
|