rocketjob 3.3.1 → 3.3.2
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/lib/rocket_job/active_worker.rb +1 -1
- data/lib/rocket_job/cli.rb +2 -2
- data/lib/rocket_job/dirmon_entry.rb +1 -1
- data/lib/rocket_job/jobs/housekeeping_job.rb +2 -2
- data/lib/rocket_job/plugins/job/persistence.rb +8 -7
- data/lib/rocket_job/plugins/job/state_machine.rb +3 -3
- data/lib/rocket_job/plugins/job/throttle_running_jobs.rb +2 -2
- data/lib/rocket_job/plugins/restart.rb +1 -1
- data/lib/rocket_job/plugins/retry.rb +16 -12
- data/lib/rocket_job/plugins/rufus/cron_line.rb +1 -0
- data/lib/rocket_job/plugins/rufus/zo_time.rb +1 -0
- data/lib/rocket_job/server.rb +8 -7
- data/lib/rocket_job/version.rb +1 -1
- data/lib/rocketjob.rb +1 -0
- data/test/plugins/job/throttle_test.rb +4 -4
- data/test/plugins/retry_test.rb +89 -0
- data/test/plugins/transaction_test.rb +3 -3
- data/test/test_db.sqlite3 +0 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39e1ecc5af4c504fb096f81dd86504bbd80d2336
|
4
|
+
data.tar.gz: 0b25172aa4de31ae79713a7c5427d1c985163384
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62efb08e25832d84977ec3060982167c0e6958d4b9380f8ecf67f7a64c18b1a4be2765e086bc9d07cade9edaf6a3d8077a725329df6c1c27543d35072b0918c1
|
7
|
+
data.tar.gz: 3f4380575fc99756a2fd63f9d84f571c9ff1ce12dbeab8d642aacd2c4c4b04a54ba98416d6d04dd00760aeb59427304815a755e0dc205770fcf8293776db97cc
|
@@ -16,7 +16,7 @@ module RocketJob
|
|
16
16
|
def self.all(server_name = nil)
|
17
17
|
servers = []
|
18
18
|
# Need paused, failed or aborted since servers may still be working on active slices
|
19
|
-
query
|
19
|
+
query = RocketJob::Job.where(:state.in => [:running, :paused, :failed, :aborted])
|
20
20
|
query = query.where(worker_name: /\A#{server_name}/) if server_name
|
21
21
|
query.each do |job|
|
22
22
|
servers += job.rocket_job_active_workers
|
data/lib/rocket_job/cli.rb
CHANGED
@@ -7,8 +7,8 @@ module RocketJob
|
|
7
7
|
class CLI
|
8
8
|
include SemanticLogger::Loggable
|
9
9
|
attr_accessor :name, :workers, :environment, :pidfile, :directory, :quiet,
|
10
|
-
|
11
|
-
|
10
|
+
:log_level, :log_file, :mongo_config, :symmetric_encryption_config,
|
11
|
+
:filter
|
12
12
|
|
13
13
|
def initialize(argv)
|
14
14
|
@name = nil
|
@@ -234,7 +234,7 @@ module RocketJob
|
|
234
234
|
next if file_name.include?(self.class.default_archive_directory)
|
235
235
|
|
236
236
|
# Security check?
|
237
|
-
if (whitelist_paths.size > 0) && whitelist_paths.none? {|whitepath| file_name.to_s.start_with?(whitepath)}
|
237
|
+
if (whitelist_paths.size > 0) && whitelist_paths.none? { |whitepath| file_name.to_s.start_with?(whitepath) }
|
238
238
|
logger.error "Skipping file: #{file_name} since it is not in any of the whitelisted paths: #{whitelist_paths.join(', ')}"
|
239
239
|
next
|
240
240
|
end
|
@@ -29,8 +29,8 @@ module RocketJob
|
|
29
29
|
include RocketJob::Plugins::Cron
|
30
30
|
include RocketJob::Plugins::Singleton
|
31
31
|
|
32
|
-
self.priority
|
33
|
-
self.description
|
32
|
+
self.priority = 25
|
33
|
+
self.description = 'Cleans out historical jobs, and zombie servers.'
|
34
34
|
# Runs every 15 minutes
|
35
35
|
self.cron_schedule = '*/15 * * * * UTC'
|
36
36
|
|
@@ -70,14 +70,15 @@ module RocketJob
|
|
70
70
|
# }
|
71
71
|
def counts_by_state
|
72
72
|
counts = {}
|
73
|
-
collection.aggregate(
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
73
|
+
collection.aggregate(
|
74
|
+
[
|
75
|
+
{
|
76
|
+
'$group' => {
|
77
|
+
_id: '$state',
|
78
|
+
count: {'$sum' => 1}
|
79
|
+
}
|
78
80
|
}
|
79
|
-
|
80
|
-
]
|
81
|
+
]
|
81
82
|
).each do |result|
|
82
83
|
counts[result['_id'].to_sym] = result['count']
|
83
84
|
end
|
@@ -77,9 +77,9 @@ module RocketJob
|
|
77
77
|
end
|
78
78
|
|
79
79
|
event :requeue do
|
80
|
-
transitions from:
|
81
|
-
|
82
|
-
|
80
|
+
transitions from: :running, to: :queued,
|
81
|
+
if: -> server_name { worker_on_server?(server_name) },
|
82
|
+
after: :rocket_job_clear_started_at
|
83
83
|
end
|
84
84
|
end
|
85
85
|
# @formatter:on
|
@@ -38,8 +38,8 @@ module RocketJob
|
|
38
38
|
def throttle_running_jobs_exceeded?
|
39
39
|
throttle_running_jobs &&
|
40
40
|
(throttle_running_jobs != 0) &&
|
41
|
-
|
42
|
-
|
41
|
+
# Cannot use the class since it will include instances of parent job classes.
|
42
|
+
(RocketJob::Job.running.where('_type' => self.class.name, :id.ne => id).count >= throttle_running_jobs)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -25,7 +25,7 @@ module RocketJob
|
|
25
25
|
# include RocketJob::Plugins::Retry
|
26
26
|
#
|
27
27
|
# # Set the default retry_count
|
28
|
-
# self.
|
28
|
+
# self.retry_limit = 3
|
29
29
|
#
|
30
30
|
# def perform
|
31
31
|
# puts "DONE"
|
@@ -36,10 +36,10 @@ module RocketJob
|
|
36
36
|
# MyJob.create!
|
37
37
|
#
|
38
38
|
# # Replace the default retry_count
|
39
|
-
# MyCronJob.create!(
|
39
|
+
# MyCronJob.create!(retry_limit: 10)
|
40
40
|
#
|
41
41
|
# # Disable retries for this job instance
|
42
|
-
# MyCronJob.create!(
|
42
|
+
# MyCronJob.create!(retry_limit: 0)
|
43
43
|
#
|
44
44
|
module Retry
|
45
45
|
extend ActiveSupport::Concern
|
@@ -49,17 +49,21 @@ module RocketJob
|
|
49
49
|
|
50
50
|
# Maximum number of times to retry this job
|
51
51
|
# 25 is approximately 3 weeks of retries
|
52
|
-
field :
|
52
|
+
field :retry_limit, type: Integer, default: 25, class_attribute: true, user_editable: true, copy_on_restart: true
|
53
53
|
|
54
54
|
# List of times when this job failed
|
55
|
-
field :
|
55
|
+
field :failed_at_list, type: Array, default: []
|
56
56
|
|
57
|
-
validates_presence_of :
|
57
|
+
validates_presence_of :retry_limit
|
58
58
|
end
|
59
59
|
|
60
|
-
# Returns [true|false] whether this job
|
60
|
+
# Returns [true|false] whether this job should be retried on failure.
|
61
61
|
def rocket_job_retry_on_fail?
|
62
|
-
|
62
|
+
rocket_job_failure_count < retry_limit
|
63
|
+
end
|
64
|
+
|
65
|
+
def rocket_job_failure_count
|
66
|
+
failed_at_list.size
|
63
67
|
end
|
64
68
|
|
65
69
|
private
|
@@ -73,8 +77,8 @@ module RocketJob
|
|
73
77
|
|
74
78
|
now = Time.now
|
75
79
|
self.run_at = now + delay_seconds
|
76
|
-
self.
|
77
|
-
new_record? ? retry : retry!
|
80
|
+
self.failed_at_list << now
|
81
|
+
new_record? ? self.retry : self.retry!
|
78
82
|
end
|
79
83
|
|
80
84
|
# Prevent exception from being cleared on retry
|
@@ -85,9 +89,9 @@ module RocketJob
|
|
85
89
|
end
|
86
90
|
|
87
91
|
# Returns [Time] when to retry this job at
|
88
|
-
# Same basic formula as
|
92
|
+
# Same basic formula as Delayed Job
|
89
93
|
def rocket_job_retry_seconds_to_delay
|
90
|
-
(
|
94
|
+
(rocket_job_failure_count ** 4) + 15 + (rand(30) * (rocket_job_failure_count + 1))
|
91
95
|
end
|
92
96
|
|
93
97
|
end
|
data/lib/rocket_job/server.rb
CHANGED
@@ -141,14 +141,15 @@ module RocketJob
|
|
141
141
|
# # => {}
|
142
142
|
def self.counts_by_state
|
143
143
|
counts = {}
|
144
|
-
collection.aggregate(
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
144
|
+
collection.aggregate(
|
145
|
+
[
|
146
|
+
{
|
147
|
+
'$group' => {
|
148
|
+
_id: '$state',
|
149
|
+
count: {'$sum' => 1}
|
150
|
+
}
|
149
151
|
}
|
150
|
-
|
151
|
-
]
|
152
|
+
]
|
152
153
|
).each do |result|
|
153
154
|
counts[result['_id'].to_sym] = result['count']
|
154
155
|
end
|
data/lib/rocket_job/version.rb
CHANGED
data/lib/rocketjob.rb
CHANGED
@@ -38,6 +38,7 @@ module RocketJob
|
|
38
38
|
autoload :Document, 'rocket_job/plugins/document'
|
39
39
|
autoload :ProcessingWindow, 'rocket_job/plugins/processing_window'
|
40
40
|
autoload :Restart, 'rocket_job/plugins/restart'
|
41
|
+
autoload :Retry, 'rocket_job/plugins/retry'
|
41
42
|
autoload :Singleton, 'rocket_job/plugins/singleton'
|
42
43
|
autoload :StateMachine, 'rocket_job/plugins/state_machine'
|
43
44
|
autoload :Transaction, 'rocket_job/plugins/transaction'
|
@@ -86,15 +86,15 @@ module Plugins
|
|
86
86
|
ThrottleJob.create!(state: :failed)
|
87
87
|
ThrottleJob.create!(state: :complete)
|
88
88
|
ThrottleJob.create!(state: :paused)
|
89
|
-
assert job = RocketJob::Job.rocket_job_next_job(@worker_name), -> {ThrottleJob.all.to_a.ai}
|
90
|
-
assert_equal @job.id, job.id, -> {ThrottleJob.all.to_a.ai}
|
89
|
+
assert job = RocketJob::Job.rocket_job_next_job(@worker_name), -> { ThrottleJob.all.to_a.ai }
|
90
|
+
assert_equal @job.id, job.id, -> { ThrottleJob.all.to_a.ai }
|
91
91
|
end
|
92
92
|
|
93
93
|
it 'return nil when other jobs are running' do
|
94
94
|
ThrottleJob.create!
|
95
95
|
@job = ThrottleJob.new
|
96
96
|
@job.start!
|
97
|
-
assert_nil RocketJob::Job.rocket_job_next_job(@worker_name), -> {ThrottleJob.all.to_a.ai}
|
97
|
+
assert_nil RocketJob::Job.rocket_job_next_job(@worker_name), -> { ThrottleJob.all.to_a.ai }
|
98
98
|
end
|
99
99
|
|
100
100
|
it 'add job to filter when other jobs are running' do
|
@@ -102,7 +102,7 @@ module Plugins
|
|
102
102
|
@job = ThrottleJob.new
|
103
103
|
@job.start!
|
104
104
|
filter = {}
|
105
|
-
assert_nil RocketJob::Job.rocket_job_next_job(@worker_name, filter), -> {ThrottleJob.all.to_a.ai}
|
105
|
+
assert_nil RocketJob::Job.rocket_job_next_job(@worker_name, filter), -> { ThrottleJob.all.to_a.ai }
|
106
106
|
assert_equal 1, filter.size
|
107
107
|
end
|
108
108
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
module Plugins
|
4
|
+
class RetryTest < Minitest::Test
|
5
|
+
class RetryJob < RocketJob::Job
|
6
|
+
include RocketJob::Plugins::Retry
|
7
|
+
|
8
|
+
# Fails 5 times before succeeding
|
9
|
+
def perform
|
10
|
+
raise "Oh No" unless rocket_job_failure_count >= 5
|
11
|
+
'DONE'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe RocketJob::Plugins::Retry do
|
16
|
+
before do
|
17
|
+
RetryJob.delete_all
|
18
|
+
end
|
19
|
+
|
20
|
+
after do
|
21
|
+
@job.delete if @job && !@job.new_record?
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#perform' do
|
25
|
+
it 're-queues job on failure' do
|
26
|
+
@job = RetryJob.create!
|
27
|
+
assert created_at = @job.created_at
|
28
|
+
assert_equal 0, @job.failed_at_list.size
|
29
|
+
|
30
|
+
assert_raises RuntimeError do
|
31
|
+
@job.perform_now
|
32
|
+
end
|
33
|
+
|
34
|
+
assert @job.queued?, -> { @job.attributes.ai }
|
35
|
+
|
36
|
+
# Includes failure time
|
37
|
+
assert_equal 1, @job.rocket_job_failure_count
|
38
|
+
assert failed_at = @job.failed_at_list.first
|
39
|
+
assert failed_at >= created_at
|
40
|
+
|
41
|
+
assert next_time = @job.run_at
|
42
|
+
assert next_time > failed_at
|
43
|
+
end
|
44
|
+
|
45
|
+
it 're-queues until it succeeds' do
|
46
|
+
@job = RetryJob.create!
|
47
|
+
|
48
|
+
# 5 retries
|
49
|
+
5.times do |i|
|
50
|
+
assert_raises RuntimeError do
|
51
|
+
@job.perform_now
|
52
|
+
end
|
53
|
+
assert @job.queued?, -> { @job.attributes.ai }
|
54
|
+
assert_equal (i + 1), @job.rocket_job_failure_count
|
55
|
+
end
|
56
|
+
|
57
|
+
assert_equal 5, @job.rocket_job_failure_count
|
58
|
+
|
59
|
+
# Should succeed on the 6th attempt
|
60
|
+
@job.perform_now
|
61
|
+
assert @job.completed?, -> { @job.attributes.ai }
|
62
|
+
assert_equal 5, @job.rocket_job_failure_count
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'stops re-queueing after limit is reached' do
|
66
|
+
@job = RetryJob.create!(retry_limit: 3)
|
67
|
+
|
68
|
+
# 3 attempts are retried
|
69
|
+
3.times do |i|
|
70
|
+
assert_raises RuntimeError do
|
71
|
+
@job.perform_now
|
72
|
+
end
|
73
|
+
assert @job.queued?, -> { @job.attributes.ai }
|
74
|
+
assert_equal (i + 1), @job.rocket_job_failure_count
|
75
|
+
end
|
76
|
+
|
77
|
+
# Should fail on the 4th attempt
|
78
|
+
assert_equal 3, @job.rocket_job_failure_count
|
79
|
+
assert_raises RuntimeError do
|
80
|
+
@job.perform_now
|
81
|
+
end
|
82
|
+
|
83
|
+
assert @job.failed?, -> { @job.attributes.ai }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -53,9 +53,9 @@ module Plugins
|
|
53
53
|
|
54
54
|
describe '#rocket_job_transaction' do
|
55
55
|
it 'is registered' do
|
56
|
-
assert CommitTransactionJob.send(:get_callbacks, :perform).find {|c| c.filter == :rocket_job_transaction}
|
57
|
-
assert RollbackTransactionJob.send(:get_callbacks, :perform).find {|c| c.filter == :rocket_job_transaction}
|
58
|
-
refute RocketJob::Job.send(:get_callbacks, :perform).find {|c| c.filter == :rocket_job_transaction}
|
56
|
+
assert CommitTransactionJob.send(:get_callbacks, :perform).find { |c| c.filter == :rocket_job_transaction }
|
57
|
+
assert RollbackTransactionJob.send(:get_callbacks, :perform).find { |c| c.filter == :rocket_job_transaction }
|
58
|
+
refute RocketJob::Job.send(:get_callbacks, :perform).find { |c| c.filter == :rocket_job_transaction }
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
data/test/test_db.sqlite3
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rocketjob
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.3.
|
4
|
+
version: 3.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Reid Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -135,6 +135,7 @@ files:
|
|
135
135
|
- test/plugins/job/worker_test.rb
|
136
136
|
- test/plugins/processing_window_test.rb
|
137
137
|
- test/plugins/restart_test.rb
|
138
|
+
- test/plugins/retry_test.rb
|
138
139
|
- test/plugins/singleton_test.rb
|
139
140
|
- test/plugins/state_machine_event_callbacks_test.rb
|
140
141
|
- test/plugins/state_machine_test.rb
|
@@ -185,6 +186,7 @@ test_files:
|
|
185
186
|
- test/plugins/job/worker_test.rb
|
186
187
|
- test/plugins/processing_window_test.rb
|
187
188
|
- test/plugins/restart_test.rb
|
189
|
+
- test/plugins/retry_test.rb
|
188
190
|
- test/plugins/singleton_test.rb
|
189
191
|
- test/plugins/state_machine_event_callbacks_test.rb
|
190
192
|
- test/plugins/state_machine_test.rb
|