rocketjob 1.3.0 → 2.0.0.rc1

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +201 -0
  3. data/README.md +15 -10
  4. data/bin/rocketjob +3 -1
  5. data/bin/rocketjob_perf +92 -0
  6. data/lib/rocket_job/cli.rb +71 -31
  7. data/lib/rocket_job/config.rb +21 -23
  8. data/lib/rocket_job/dirmon_entry.rb +63 -45
  9. data/lib/rocket_job/extensions/aasm.rb +56 -0
  10. data/lib/rocket_job/extensions/mongo.rb +23 -0
  11. data/lib/rocket_job/job.rb +9 -433
  12. data/lib/rocket_job/jobs/dirmon_job.rb +20 -20
  13. data/lib/rocket_job/jobs/simple_job.rb +12 -0
  14. data/lib/rocket_job/plugins/document.rb +69 -0
  15. data/lib/rocket_job/plugins/job/callbacks.rb +92 -0
  16. data/lib/rocket_job/plugins/job/defaults.rb +40 -0
  17. data/lib/rocket_job/plugins/job/logger.rb +36 -0
  18. data/lib/rocket_job/plugins/job/model.rb +288 -0
  19. data/lib/rocket_job/plugins/job/persistence.rb +167 -0
  20. data/lib/rocket_job/plugins/job/state_machine.rb +166 -0
  21. data/lib/rocket_job/plugins/job/worker.rb +167 -0
  22. data/lib/rocket_job/plugins/restart.rb +54 -0
  23. data/lib/rocket_job/plugins/singleton.rb +26 -0
  24. data/lib/rocket_job/plugins/state_machine.rb +105 -0
  25. data/lib/rocket_job/version.rb +1 -1
  26. data/lib/rocket_job/worker.rb +150 -119
  27. data/lib/rocketjob.rb +43 -21
  28. data/test/config_test.rb +12 -0
  29. data/test/dirmon_entry_test.rb +81 -85
  30. data/test/dirmon_job_test.rb +40 -28
  31. data/test/job_test.rb +14 -257
  32. data/test/plugins/job/callbacks_test.rb +163 -0
  33. data/test/plugins/job/defaults_test.rb +52 -0
  34. data/test/plugins/job/logger_test.rb +58 -0
  35. data/test/plugins/job/model_test.rb +97 -0
  36. data/test/plugins/job/persistence_test.rb +81 -0
  37. data/test/plugins/job/state_machine_test.rb +118 -0
  38. data/test/plugins/job/worker_test.rb +183 -0
  39. data/test/plugins/restart_test.rb +185 -0
  40. data/test/plugins/singleton_test.rb +94 -0
  41. data/test/plugins/state_machine_event_callbacks_test.rb +101 -0
  42. data/test/plugins/state_machine_test.rb +64 -0
  43. data/test/test_helper.rb +3 -36
  44. metadata +64 -19
  45. data/lib/rocket_job/concerns/singleton.rb +0 -33
  46. data/lib/rocket_job/concerns/worker.rb +0 -214
  47. data/test/files/_archive/archived.txt +0 -3
  48. data/test/job_worker_test.rb +0 -86
  49. data/test/jobs/test_job.rb +0 -46
  50. data/test/worker_test.rb +0 -97
@@ -1,17 +1,34 @@
1
1
  require_relative 'test_helper'
2
- require_relative 'jobs/test_job'
3
2
 
4
3
  # Unit Test for RocketJob::Job
5
4
  class DirmonEntryTest < Minitest::Test
5
+
6
+ class OneArgumentJob < RocketJob::Job
7
+ def perform(arg)
8
+ end
9
+ end
10
+
6
11
  class WithFullFileNameJob < RocketJob::Job
7
12
  # Dirmon will store the filename in this property when starting the job
8
- key :full_file_name, String
13
+ key :upload_file_name, String
9
14
 
10
15
  def perform
11
- # Do something with the file name stored in :full_file_name
16
+ # Do something with the file name stored in :upload_file_name
12
17
  end
13
18
  end
14
19
 
20
+ class SumJob < RocketJob::Job
21
+ @@result = nil
22
+
23
+ # For temp test data
24
+ def self.result
25
+ @@result
26
+ end
27
+
28
+ def perform(a, b)
29
+ @@result = a + b
30
+ end
31
+ end
15
32
 
16
33
  describe RocketJob::DirmonEntry do
17
34
  describe '.config' do
@@ -57,31 +74,33 @@ class DirmonEntryTest < Minitest::Test
57
74
  end
58
75
 
59
76
  it 'convert relative path to an absolute one' do
60
- path = Pathname('test/jobs').realpath.to_s
61
- assert_equal path, RocketJob::DirmonEntry.add_whitelist_path('test/jobs')
77
+ path = Pathname('test/files').realpath.to_s
78
+ assert_equal path, RocketJob::DirmonEntry.add_whitelist_path('test/files')
62
79
  assert_equal [path], RocketJob::DirmonEntry.whitelist_paths
63
80
  end
64
81
 
65
82
  it 'prevent duplicates' do
66
- path = Pathname('test/jobs').realpath.to_s
67
- assert_equal path, RocketJob::DirmonEntry.add_whitelist_path('test/jobs')
68
- assert_equal path, RocketJob::DirmonEntry.add_whitelist_path('test/jobs')
83
+ path = Pathname('test/files').realpath.to_s
84
+ assert_equal path, RocketJob::DirmonEntry.add_whitelist_path('test/files')
85
+ assert_equal path, RocketJob::DirmonEntry.add_whitelist_path('test/files')
69
86
  assert_equal path, RocketJob::DirmonEntry.add_whitelist_path(path)
70
87
  assert_equal [path], RocketJob::DirmonEntry.whitelist_paths
71
88
  end
72
89
  end
73
90
 
74
- describe '#fail_with_exception!' do
91
+ describe '#fail!' do
75
92
  before do
76
- @dirmon_entry = RocketJob::DirmonEntry.new(job_class_name: 'Jobs::TestJob', pattern: 'test/files/**', arguments: [1])
93
+ @dirmon_entry = RocketJob::DirmonEntry.new(job_class_name: 'DirmonEntryTest::OneArgumentJob', pattern: 'test/files/**', arguments: [1])
77
94
  @dirmon_entry.enable!
95
+ assert @dirmon_entry.valid?, @dirmon_entry.errors.messages.ai
78
96
  end
97
+
79
98
  after do
80
99
  @dirmon_entry.destroy if @dirmon_entry && @dirmon_entry.new_record?
81
100
  end
82
101
 
83
102
  it 'fail with message' do
84
- @dirmon_entry.fail_with_exception!('myworker:2323', 'oh no')
103
+ @dirmon_entry.fail!('myworker:2323', 'oh no')
85
104
  assert_equal true, @dirmon_entry.failed?
86
105
  assert_equal 'RocketJob::DirmonEntryException', @dirmon_entry.exception.class_name
87
106
  assert_equal 'oh no', @dirmon_entry.exception.message
@@ -94,7 +113,7 @@ class DirmonEntryTest < Minitest::Test
94
113
  rescue Exception => exc
95
114
  exception = exc
96
115
  end
97
- @dirmon_entry.fail_with_exception!('myworker:2323', exception)
116
+ @dirmon_entry.fail!('myworker:2323', exception)
98
117
 
99
118
  assert_equal true, @dirmon_entry.failed?
100
119
  assert_equal exception.class.name.to_s, @dirmon_entry.exception.class_name
@@ -104,107 +123,84 @@ class DirmonEntryTest < Minitest::Test
104
123
 
105
124
  describe '#validate' do
106
125
  it 'existance' do
107
- assert entry = RocketJob::DirmonEntry.new(job_class_name: 'Jobs::TestJob')
126
+ assert entry = RocketJob::DirmonEntry.new(job_class_name: 'DirmonEntryTest::OneArgumentJob')
108
127
  assert_equal false, entry.valid?
109
- assert_equal ["can't be blank"], entry.errors[:pattern], entry.errors.inspect
110
- end
111
-
112
- describe 'perform_method' do
113
- describe 'with an invalid method' do
114
- it 'add errors to the entry' do
115
- entry = RocketJob::DirmonEntry.new(job_class_name: 'Jobs::TestJob', perform_method: :missing_perform_method)
116
- assert_equal false, entry.valid?
117
- assert_equal ['Method not implemented by Jobs::TestJob'], entry.errors[:perform_method], entry.errors.inspect
118
- end
119
- end
128
+ assert_equal ["can't be blank"], entry.errors[:pattern], entry.errors.messages.ai
120
129
  end
121
130
 
122
131
  describe 'job_class_name' do
123
132
  it 'ensure presence' do
124
133
  assert entry = RocketJob::DirmonEntry.new(pattern: 'test/files/**')
125
134
  assert_equal false, entry.valid?
126
- assert_equal ["can't be blank", 'job_class_name must be defined and must be derived from RocketJob::Job'], entry.errors[:job_class_name], entry.errors.inspect
135
+ assert_equal ["can't be blank", 'job_class_name must be defined and must be derived from RocketJob::Job'], entry.errors[:job_class_name], entry.errors.messages.ai
127
136
  end
128
137
  end
129
138
 
130
139
  describe 'arguments' do
131
140
  it 'allow no arguments' do
132
141
  assert entry = RocketJob::DirmonEntry.new(
133
- job_class_name: 'Jobs::TestJob',
134
- pattern: 'test/files/**',
135
- perform_method: :result
136
- )
137
- assert_equal true, entry.valid?, entry.errors.inspect
138
- assert_equal [], entry.errors[:arguments], entry.errors.inspect
142
+ job_class_name: 'DirmonEntryTest::WithFullFileNameJob',
143
+ pattern: 'test/files/**'
144
+ )
145
+ assert entry.valid?, entry.errors.messages.ai
139
146
  end
140
147
 
141
148
  it 'ensure correct number of arguments' do
142
149
  assert entry = RocketJob::DirmonEntry.new(
143
- job_class_name: 'Jobs::TestJob',
144
- pattern: 'test/files/**'
145
- )
146
- assert_equal false, entry.valid?
147
- assert_equal ['There must be 1 argument(s)'], entry.errors[:arguments], entry.errors.inspect
150
+ job_class_name: 'DirmonEntryTest::OneArgumentJob',
151
+ pattern: 'test/files/**'
152
+ )
153
+ refute entry.valid?
154
+ assert_equal ['There must be 1 argument(s)'], entry.errors[:arguments], entry.errors.messages.ai
148
155
  end
149
156
 
150
- it 'return false if the job name is bad' do
157
+ it 'fail if the job name is bad' do
151
158
  assert entry = RocketJob::DirmonEntry.new(
152
- job_class_name: 'Jobs::Tests::Names::Things',
153
- pattern: 'test/files/**'
154
- )
155
- assert_equal false, entry.valid?
156
- assert_equal [], entry.errors[:arguments], entry.errors.inspect
157
- end
158
- end
159
-
160
- it 'arguments with perform_method' do
161
- assert entry = RocketJob::DirmonEntry.new(
162
- job_class_name: 'Jobs::TestJob',
163
- pattern: 'test/files/**',
164
- perform_method: :sum
159
+ job_class_name: 'Jobs::Tests::Names::Things',
160
+ pattern: 'test/files/**'
165
161
  )
166
- assert_equal false, entry.valid?
167
- assert_equal ['There must be 2 argument(s)'], entry.errors[:arguments], entry.errors.inspect
162
+ refute entry.valid?
163
+ assert_equal [], entry.errors[:arguments], entry.errors.messages.ai
164
+ end
168
165
  end
169
166
 
170
- it 'valid' do
167
+ it 'invalid without 2 arguments' do
171
168
  assert entry = RocketJob::DirmonEntry.new(
172
- job_class_name: 'Jobs::TestJob',
173
- pattern: 'test/files/**',
174
- arguments: [1]
175
- )
176
- assert entry.valid?, entry.errors.inspect
169
+ job_class_name: 'DirmonEntryTest::SumJob',
170
+ pattern: 'test/files/**'
171
+ )
172
+ refute entry.valid?
173
+ assert_equal ['There must be 2 argument(s)'], entry.errors[:arguments], entry.errors.messages.ai
177
174
  end
178
175
 
179
- it 'valid with perform_method' do
176
+ it 'valid with 2 arguments' do
180
177
  assert entry = RocketJob::DirmonEntry.new(
181
- job_class_name: 'Jobs::TestJob',
182
- pattern: 'test/files/**',
183
- perform_method: :sum,
184
- arguments: [1, 2]
185
- )
186
- assert entry.valid?, entry.errors.inspect
178
+ job_class_name: 'DirmonEntryTest::SumJob',
179
+ pattern: 'test/files/**',
180
+ arguments: [1, 2]
181
+ )
182
+ assert entry.valid?, entry.errors.messages.ai
187
183
  end
188
184
  end
189
185
 
190
186
  describe 'with valid entry' do
191
187
  before do
188
+ RocketJob::Jobs::DirmonJob.delete_all
192
189
  @archive_directory = '/tmp/archive_directory'
193
190
  @archive_path = Pathname.new(@archive_directory)
194
191
  @archive_path.mkpath
195
192
  @archive_path = @archive_path.realdirpath
196
193
  @entry = RocketJob::DirmonEntry.new(
197
194
  pattern: 'test/files/**/*',
198
- job_class_name: 'Jobs::TestJob',
195
+ job_class_name: 'RocketJob::Jobs::DirmonJob',
199
196
  arguments: [{}],
200
- properties: {priority: 23, perform_method: :event},
197
+ properties: {priority: 23},
201
198
  archive_directory: @archive_directory
202
199
  )
203
- @job = Jobs::TestJob.new(
200
+ @job = DirmonEntryTest::OneArgumentJob.new(
204
201
  @entry.properties.merge(
205
- arguments: @entry.arguments,
206
- properties: @entry.properties,
207
- perform_method: @entry.perform_method
202
+ arguments: @entry.arguments,
203
+ properties: @entry.properties
208
204
  )
209
205
  )
210
206
  @file = Tempfile.new('archive')
@@ -217,6 +213,7 @@ class DirmonEntryTest < Minitest::Test
217
213
 
218
214
  after do
219
215
  @file.delete if @file
216
+ RocketJob::Jobs::DirmonJob.delete_all
220
217
  end
221
218
 
222
219
  describe '#archive_pathname' do
@@ -243,7 +240,7 @@ class DirmonEntryTest < Minitest::Test
243
240
  assert_equal @archive_real_name, @job.arguments.first[:full_file_name], @job.arguments
244
241
  end
245
242
 
246
- it 'sets full_file_name property' do
243
+ it 'sets upload_file_name property' do
247
244
  @entry = RocketJob::DirmonEntry.new(
248
245
  pattern: 'test/files/**/*',
249
246
  job_class_name: 'DirmonEntryTest::WithFullFileNameJob',
@@ -253,7 +250,7 @@ class DirmonEntryTest < Minitest::Test
253
250
  job = @entry.job_class.new
254
251
  @entry.send(:upload_default, job, @pathname)
255
252
  archive_real_name = @archive_path.join("#{job.id}_#{File.basename(@file_name)}").to_s
256
- assert_equal archive_real_name, job.full_file_name, job.arguments
253
+ assert_equal archive_real_name, job.upload_file_name, job.arguments
257
254
  end
258
255
 
259
256
  it 'handles non hash argument and missing property' do
@@ -265,14 +262,6 @@ class DirmonEntryTest < Minitest::Test
265
262
  end
266
263
 
267
264
  describe '#upload_file' do
268
- it 'upload using #file_store_upload' do
269
- @job.define_singleton_method(:file_store_upload) do |file_name|
270
- self.description = "FILE:#{file_name}"
271
- end
272
- @entry.send(:upload_file, @job, @pathname)
273
- assert_equal "FILE:#{@file_name}", @job.description
274
- end
275
-
276
265
  it 'upload using #upload' do
277
266
  @job.define_singleton_method(:upload) do |file_name|
278
267
  self.description = "FILE:#{file_name}"
@@ -283,13 +272,20 @@ class DirmonEntryTest < Minitest::Test
283
272
  end
284
273
 
285
274
  describe '#later' do
286
- it 'enqueue job' do
287
- @entry.arguments = [{}]
288
- @entry.perform_method = :event
289
- job = @entry.later(@pathname)
275
+ it 'enqueues job' do
276
+ @entry.arguments = [{}]
277
+ job = @entry.later(@pathname)
290
278
  assert_equal Pathname.new(@archive_directory).join("#{job.id}_#{File.basename(@file_name)}").realdirpath.to_s, job.arguments.first[:full_file_name]
291
279
  assert job.queued?
292
280
  end
281
+
282
+ it 'fails with bad job class name' do
283
+ @entry.arguments = [{}]
284
+ @entry.job_class_name = 'Blah'
285
+ assert_raises ArgumentError do
286
+ @entry.later(@pathname)
287
+ end
288
+ end
293
289
  end
294
290
 
295
291
  describe '#each' do
@@ -1,18 +1,24 @@
1
1
  require_relative 'test_helper'
2
- require_relative 'jobs/test_job'
3
2
 
4
3
  # Unit Test for RocketJob::Job
5
4
  class DirmonJobTest < Minitest::Test
5
+ class DirmonTestJob < RocketJob::Job
6
+ def perform(hash)
7
+ 3645
8
+ end
9
+ end
10
+
6
11
  describe RocketJob::Jobs::DirmonJob do
7
12
  before do
13
+ RocketJob::Jobs::DirmonJob.delete_all
8
14
  @dirmon_job = RocketJob::Jobs::DirmonJob.new
9
15
  @directory = '/tmp/directory'
10
16
  @archive_directory = '/tmp/archive_directory'
11
17
  @entry = RocketJob::DirmonEntry.new(
12
18
  pattern: "#{@directory}/abc/*",
13
- job_class_name: 'Jobs::TestJob',
19
+ job_class_name: 'DirmonJobTest::DirmonTestJob',
14
20
  arguments: [{input: 'yes'}],
15
- properties: {priority: 23, perform_method: :event},
21
+ properties: {priority: 23},
16
22
  archive_directory: @archive_directory
17
23
  )
18
24
  FileUtils.makedirs("#{@directory}/abc")
@@ -20,7 +26,7 @@ class DirmonJobTest < Minitest::Test
20
26
  end
21
27
 
22
28
  after do
23
- @dirmon_job.destroy if @dirmon_job && !@dirmon_job.new_record?
29
+ @dirmon_job.delete if @dirmon_job && !@dirmon_job.new_record?
24
30
  FileUtils.remove_dir(@archive_directory, true) if Dir.exist?(@archive_directory)
25
31
  FileUtils.remove_dir(@directory, true) if Dir.exist?(@directory)
26
32
  end
@@ -57,8 +63,9 @@ class DirmonJobTest < Minitest::Test
57
63
  it 'check deleted file' do
58
64
  previous_size = 5
59
65
  file_name = Pathname.new('blah')
60
- result = @dirmon_job.send(:check_file, @entry, file_name, previous_size)
61
- assert_equal nil, result
66
+ assert_raises Errno::ENOENT do
67
+ @dirmon_job.send(:check_file, @entry, file_name, previous_size)
68
+ end
62
69
  end
63
70
  end
64
71
 
@@ -137,7 +144,6 @@ class DirmonJobTest < Minitest::Test
137
144
 
138
145
  describe '#perform' do
139
146
  it 'check directories and reschedule' do
140
- dirmon_job = nil
141
147
  previous_file_names = {
142
148
  "#{@directory}/abc/file1" => 5,
143
149
  "#{@directory}/abc/file2" => 10,
@@ -146,22 +152,24 @@ class DirmonJobTest < Minitest::Test
146
152
  "#{@directory}/abc/file1" => 10,
147
153
  "#{@directory}/abc/file2" => 10,
148
154
  }
149
- RocketJob::Jobs::DirmonJob.destroy_all
155
+ assert_equal 0, RocketJob::Jobs::DirmonJob.count
156
+ # perform_now does not save the job, just runs it
157
+ @dirmon_job = RocketJob::Jobs::DirmonJob.create!(
158
+ previous_file_names: previous_file_names,
159
+ priority: 11,
160
+ check_seconds: 30
161
+ )
150
162
  RocketJob::Jobs::DirmonJob.stub_any_instance(:check_directories, new_file_names) do
151
- # perform_now does not save the job, just runs it
152
- dirmon_job = RocketJob::Jobs::DirmonJob.new(
153
- previous_file_names: previous_file_names,
154
- priority: 11,
155
- check_seconds: 30
156
- )
157
- dirmon_job.work_now
163
+ @dirmon_job.perform_now
158
164
  end
159
- assert dirmon_job.completed?, dirmon_job.status.inspect
165
+ assert @dirmon_job.completed?, @dirmon_job.status.inspect
166
+ # Job must destroy on complete
167
+ refute RocketJob::Jobs::DirmonJob.find(@dirmon_job.id)
160
168
 
161
- # It it have enqueued another instance to run in the future
169
+ # Must have enqueued another instance to run in the future
162
170
  assert_equal 1, RocketJob::Jobs::DirmonJob.count
163
171
  assert new_dirmon_job = RocketJob::Jobs::DirmonJob.last
164
- assert_equal false, dirmon_job.id == new_dirmon_job.id
172
+ refute_equal @dirmon_job.id.to_s, new_dirmon_job.id.to_s
165
173
  assert new_dirmon_job.run_at
166
174
  assert_equal 11, new_dirmon_job.priority
167
175
  assert_equal 30, new_dirmon_job.check_seconds
@@ -171,20 +179,24 @@ class DirmonJobTest < Minitest::Test
171
179
  end
172
180
 
173
181
  it 'check directories and reschedule even on exception' do
174
- dirmon_job = nil
175
182
  RocketJob::Jobs::DirmonJob.destroy_all
176
- RocketJob::Jobs::DirmonJob.stub_any_instance(:check_directories, -> previous { raise RuntimeError.new("Oh no") }) do
177
- # perform_now does not save the job, just runs it
178
- dirmon_job = RocketJob::Jobs::DirmonJob.create!(
179
- priority: 11,
180
- check_seconds: 30
181
- )
182
- dirmon_job.work_now
183
+ # perform_now does not save the job, just runs it
184
+ dirmon_job = RocketJob::Jobs::DirmonJob.create!(
185
+ priority: 11,
186
+ check_seconds: 30,
187
+ destroy_on_complete: false
188
+ )
189
+ RocketJob::Jobs::DirmonJob.stub_any_instance(:check_directories, -> { raise RuntimeError.new('Oh no') }) do
190
+ assert_raises RuntimeError do
191
+ dirmon_job.perform_now
192
+ end
183
193
  end
184
- assert dirmon_job.failed?, dirmon_job.status.inspect
194
+ assert dirmon_job.aborted?, dirmon_job.status.ai
195
+ assert_equal 'RuntimeError', dirmon_job.exception.class_name, dirmon_job.exception.attributes
196
+ assert_equal 'Oh no', dirmon_job.exception.message, dirmon_job.exception.attributes
185
197
 
186
198
  # Must have enqueued another instance to run in the future
187
- assert_equal 2, RocketJob::Jobs::DirmonJob.count
199
+ assert_equal 2, RocketJob::Jobs::DirmonJob.count, RocketJob::Jobs::DirmonJob.to_a
188
200
  assert new_dirmon_job = RocketJob::Jobs::DirmonJob.last
189
201
  assert new_dirmon_job.run_at
190
202
  assert_equal 11, new_dirmon_job.priority