rocketjob 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rocket_job/cli.rb +2 -0
- data/lib/rocket_job/dirmon_entry.rb +1 -1
- data/lib/rocket_job/extensions/rocket_job_adapter.rb +69 -29
- data/lib/rocket_job/jobs/active_job.rb +15 -0
- data/lib/rocket_job/jobs/dirmon_job.rb +3 -2
- data/lib/rocket_job/jobs/housekeeping_job.rb +5 -5
- data/lib/rocket_job/plugins/cron.rb +1 -1
- data/lib/rocket_job/plugins/document.rb +0 -34
- data/lib/rocket_job/plugins/job/model.rb +48 -5
- data/lib/rocket_job/plugins/processing_window.rb +4 -3
- data/lib/rocket_job/plugins/restart.rb +73 -30
- data/lib/rocket_job/plugins/retry.rb +1 -1
- data/lib/rocket_job/rocket_job.rb +53 -0
- data/lib/rocket_job/version.rb +1 -1
- data/lib/rocket_job/worker.rb +1 -1
- data/lib/rocketjob.rb +2 -23
- data/test/plugins/restart_test.rb +7 -23
- 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: 1750c9257c4d70baebe0d97b1a8549aaf86fd61c
|
4
|
+
data.tar.gz: 027cb7272e67685d1f49eb5455723a093d40e690
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f109722d6ecb509dca6f4ca8fa4da70f85d9c06c6bf85c7ae24aad7e155a580bb643db19b0ab5ce1f4b67369f30639d83c9a830fa8a7035b077e3639b19710e
|
7
|
+
data.tar.gz: f2181de5a394b23acf108369d8c3b49b527714d3833010ff648168d61dfed49d5fc86d394f7fcfb93b2d36d1d666385c2eac31bf450ed0e7667d9b72bed0b7e4
|
data/lib/rocket_job/cli.rb
CHANGED
@@ -27,6 +27,7 @@ module RocketJob
|
|
27
27
|
# Run a RocketJob::Server from the command line
|
28
28
|
def run
|
29
29
|
Thread.current.name = 'rocketjob main'
|
30
|
+
RocketJob.server!
|
30
31
|
setup_environment
|
31
32
|
setup_logger
|
32
33
|
rails? ? boot_rails : boot_standalone
|
@@ -53,6 +54,7 @@ module RocketJob
|
|
53
54
|
# Returns [true|false] whether Rails is present
|
54
55
|
def boot_rails
|
55
56
|
logger.info "Loading Rails environment: #{environment}"
|
57
|
+
RocketJob.rails!
|
56
58
|
|
57
59
|
boot_file = Pathname.new(directory).join('config/environment.rb').expand_path
|
58
60
|
require(boot_file.to_s)
|
@@ -225,7 +225,7 @@ module RocketJob
|
|
225
225
|
|
226
226
|
# Passes each filename [Pathname] found that matches the pattern into the supplied block
|
227
227
|
def each(&block)
|
228
|
-
|
228
|
+
SemanticLogger.named_tagged(dirmon_entry: id.to_s) do
|
229
229
|
# Case insensitive filename matching
|
230
230
|
Pathname.glob(pattern, File::FNM_CASEFOLD).each do |pathname|
|
231
231
|
next if pathname.directory?
|
@@ -8,42 +8,82 @@ module ActiveJob
|
|
8
8
|
#
|
9
9
|
# To use Rocket Job set the queue_adapter config to +:rocket_job+.
|
10
10
|
#
|
11
|
-
#
|
11
|
+
# In application.rb add the following line:
|
12
|
+
# config.active_job.queue_adapter = :rocket_job
|
13
|
+
#
|
14
|
+
# Example:
|
15
|
+
#
|
16
|
+
# Create a new file in app/job/my_job.rb:
|
17
|
+
#
|
18
|
+
# class MyJob < ActiveJob::Base
|
19
|
+
# def perform(record)
|
20
|
+
# p "Received: #{record}"
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# Run the job inline to verify ActiveJob is working:
|
25
|
+
#
|
26
|
+
# MyJob.perform_now('hello world')
|
27
|
+
#
|
28
|
+
# Enqueue the job for processing:
|
29
|
+
#
|
30
|
+
# MyJob.perform_later('hello world')
|
31
|
+
#
|
32
|
+
# Enqueue the job for processing, 5 minutes from now:
|
33
|
+
#
|
34
|
+
# MyJob.set(wait: 5.minutes).perform_later('hello world')
|
35
|
+
#
|
36
|
+
# Start RocketJob server (or, restart if already running)
|
37
|
+
#
|
38
|
+
# bundle exec rocketjob
|
39
|
+
#
|
40
|
+
# Override the priority of the job:
|
41
|
+
#
|
42
|
+
# class MyJob < ActiveJob::Base
|
43
|
+
# queue_with_priority 20
|
44
|
+
#
|
45
|
+
# def perform(record)
|
46
|
+
# p "Received: #{record}"
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# Notes:
|
51
|
+
# - ActiveJobs will appear in:
|
52
|
+
# - Queued before the are processed.
|
53
|
+
# - Failed if the fail to process.
|
54
|
+
# - Scheduled if they are to be processed in the future.
|
55
|
+
# - Completed jobs will not appear in completed since the Active Job adapter
|
56
|
+
# uses the default Rocket Job `destroy_on_completion` of `false`.
|
12
57
|
class RocketJobAdapter
|
13
|
-
def enqueue(active_job) #:nodoc:
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
job.active_job_queue = active_job.queue_name
|
18
|
-
job.description = active_job.class.name
|
19
|
-
job.priority = active_job.priority if active_job.priority
|
20
|
-
end
|
21
|
-
active_job.provider_job_id = rocket_job.id.to_s
|
22
|
-
rocket_job
|
58
|
+
def self.enqueue(active_job) #:nodoc:
|
59
|
+
job = RocketJob::Jobs::ActiveJob.create!(active_job_params(active_job))
|
60
|
+
active_job.provider_job_id = job.id.to_s if active_job.respond_to?(:provider_job_id=)
|
61
|
+
job
|
23
62
|
end
|
24
63
|
|
25
|
-
def enqueue_at(active_job, timestamp) #:nodoc:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
job.run_at = Time.at(timestamp).utc
|
33
|
-
end
|
34
|
-
active_job.provider_job_id = rocket_job.id.to_s
|
35
|
-
rocket_job
|
64
|
+
def self.enqueue_at(active_job, timestamp) #:nodoc:
|
65
|
+
params = active_job_params(active_job)
|
66
|
+
params[:run_at] = Time.at(timestamp).utc
|
67
|
+
|
68
|
+
job = RocketJob::Jobs::ActiveJob.create!(params)
|
69
|
+
active_job.provider_job_id = job.id.to_s if active_job.respond_to?(:provider_job_id=)
|
70
|
+
job
|
36
71
|
end
|
37
72
|
|
38
|
-
|
39
|
-
field :active_job_id, type: String
|
40
|
-
field :active_job_class, type: String
|
41
|
-
field :active_job_queue, type: String
|
73
|
+
private
|
42
74
|
|
43
|
-
|
44
|
-
|
45
|
-
|
75
|
+
def self.active_job_params(active_job)
|
76
|
+
params = {
|
77
|
+
description: active_job.class.name,
|
78
|
+
data: active_job.serialize,
|
79
|
+
active_job_id: active_job.job_id,
|
80
|
+
active_job_class: active_job.class.name,
|
81
|
+
active_job_queue: active_job.queue_name,
|
82
|
+
}
|
83
|
+
params[:priority] = active_job.priority if active_job.respond_to?(:priority) && active_job.priority
|
84
|
+
params
|
46
85
|
end
|
86
|
+
|
47
87
|
end
|
48
88
|
end
|
49
89
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RocketJob
|
2
|
+
module Jobs
|
3
|
+
# Used to wrap an Active Job
|
4
|
+
class ActiveJob < RocketJob::Job #:nodoc:
|
5
|
+
field :data, type: Hash
|
6
|
+
field :active_job_id, type: String
|
7
|
+
field :active_job_class, type: String
|
8
|
+
field :active_job_queue, type: String
|
9
|
+
|
10
|
+
def perform
|
11
|
+
::ActiveJob::Base.execute data
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -43,9 +43,10 @@ module RocketJob
|
|
43
43
|
self.priority = 40
|
44
44
|
|
45
45
|
# Number of seconds between directory scans. Default 5 mins
|
46
|
-
field :check_seconds, type: Float, default: 300.0
|
46
|
+
field :check_seconds, type: Float, default: 300.0, copy_on_restart: true
|
47
|
+
|
47
48
|
# Hash[file_name, size]
|
48
|
-
field :previous_file_names, type: Hash, default: {}
|
49
|
+
field :previous_file_names, type: Hash, default: {}, copy_on_restart: true
|
49
50
|
|
50
51
|
before_create :set_run_at
|
51
52
|
|
@@ -36,11 +36,11 @@ module RocketJob
|
|
36
36
|
|
37
37
|
# Retention intervals in seconds
|
38
38
|
# Set to nil to not
|
39
|
-
field :aborted_retention, type: Integer, default: 7.days
|
40
|
-
field :completed_retention, type: Integer, default: 7.days
|
41
|
-
field :failed_retention, type: Integer, default: 14.days
|
42
|
-
field :paused_retention, type: Integer
|
43
|
-
field :queued_retention, type: Integer
|
39
|
+
field :aborted_retention, type: Integer, default: 7.days, user_editable: true, copy_on_restart: true
|
40
|
+
field :completed_retention, type: Integer, default: 7.days, user_editable: true, copy_on_restart: true
|
41
|
+
field :failed_retention, type: Integer, default: 14.days, user_editable: true, copy_on_restart: true
|
42
|
+
field :paused_retention, type: Integer, user_editable: true, copy_on_restart: true
|
43
|
+
field :queued_retention, type: Integer, user_editable: true, copy_on_restart: true
|
44
44
|
|
45
45
|
def perform
|
46
46
|
RocketJob::Job.aborted.where(created_at: {'$lte' => aborted_retention.seconds.ago}).destroy_all if aborted_retention
|
@@ -100,7 +100,7 @@ module RocketJob
|
|
100
100
|
included do
|
101
101
|
include Restart
|
102
102
|
|
103
|
-
field :cron_schedule, type: String, class_attribute: true, user_editable: true
|
103
|
+
field :cron_schedule, type: String, class_attribute: true, user_editable: true, copy_on_restart: true
|
104
104
|
|
105
105
|
before_create :rocket_job_set_run_at
|
106
106
|
|
@@ -9,43 +9,9 @@ module RocketJob
|
|
9
9
|
|
10
10
|
included do
|
11
11
|
store_in client: 'rocketjob'
|
12
|
-
|
13
|
-
class_attribute :user_editable_fields, instance_accessor: false
|
14
|
-
self.user_editable_fields = []
|
15
12
|
end
|
16
13
|
|
17
14
|
module ClassMethods
|
18
|
-
# Defines all the fields that are accessible on the Document
|
19
|
-
# For each field that is defined, a getter and setter will be
|
20
|
-
# added as an instance method to the Document.
|
21
|
-
#
|
22
|
-
# @example Define a field.
|
23
|
-
# field :score, :type => Integer, :default => 0
|
24
|
-
#
|
25
|
-
# @param [ Symbol ] name The name of the field.
|
26
|
-
# @param [ Hash ] options The options to pass to the field.
|
27
|
-
#
|
28
|
-
# @option options [ Class ] :type The type of the field.
|
29
|
-
# @option options [ String ] :label The label for the field.
|
30
|
-
# @option options [ Object, Proc ] :default The field's default
|
31
|
-
# @option options [ Boolean ] :class_attribute Keep the fields default in a class_attribute
|
32
|
-
# @option options [ Boolean ] :user_editable Field can be edited by end users in RJMC
|
33
|
-
#
|
34
|
-
# @return [ Field ] The generated field
|
35
|
-
def field(name, options)
|
36
|
-
if options.delete(:user_editable) == true
|
37
|
-
self.user_editable_fields += [name.to_sym] unless user_editable_fields.include?(name.to_sym)
|
38
|
-
end
|
39
|
-
if options.delete(:class_attribute) == true
|
40
|
-
class_attribute(name, instance_accessor: false)
|
41
|
-
if options.has_key?(:default)
|
42
|
-
public_send("#{name}=", options[:default])
|
43
|
-
end
|
44
|
-
options[:default] = lambda { self.class.public_send(name) }
|
45
|
-
end
|
46
|
-
super(name, options)
|
47
|
-
end
|
48
|
-
|
49
15
|
# V2 Backward compatibility
|
50
16
|
# DEPRECATED
|
51
17
|
def key(name, type, options = {})
|
@@ -8,13 +8,22 @@ module RocketJob
|
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
10
|
included do
|
11
|
+
# Fields that are end user editable.
|
12
|
+
# For example are editable in Rocket Job Mission Control.
|
13
|
+
class_attribute :user_editable_fields, instance_accessor: false
|
14
|
+
self.user_editable_fields = []
|
15
|
+
|
16
|
+
# Attributes to include when copying across the attributes to a new instance on restart.
|
17
|
+
class_attribute :rocket_job_restart_attributes
|
18
|
+
self.rocket_job_restart_attributes = []
|
19
|
+
|
11
20
|
#
|
12
21
|
# User definable attributes
|
13
22
|
#
|
14
23
|
# The following attributes are set when the job is created
|
15
24
|
|
16
25
|
# Description for this job instance
|
17
|
-
field :description, type: String, class_attribute: true, user_editable: true
|
26
|
+
field :description, type: String, class_attribute: true, user_editable: true, copy_on_restart: true
|
18
27
|
|
19
28
|
# Priority of this job as it relates to other jobs [1..100]
|
20
29
|
# 1: Highest Priority
|
@@ -27,10 +36,10 @@ module RocketJob
|
|
27
36
|
# In RocketJob Pro, if a SlicedJob is running and a higher priority job
|
28
37
|
# arrives, then the current job will complete the current slices and process
|
29
38
|
# the new higher priority job
|
30
|
-
field :priority, type: Integer, default: 50, class_attribute: true, user_editable: true
|
39
|
+
field :priority, type: Integer, default: 50, class_attribute: true, user_editable: true, copy_on_restart: true
|
31
40
|
|
32
41
|
# When the job completes destroy it from both the database and the UI
|
33
|
-
field :destroy_on_complete, type: Boolean, default: true, class_attribute: true
|
42
|
+
field :destroy_on_complete, type: Boolean, default: true, class_attribute: true, user_editable: true, copy_on_restart: true
|
34
43
|
|
35
44
|
# Whether to store the results from this job
|
36
45
|
field :collect_output, type: Boolean, default: false, class_attribute: true
|
@@ -39,13 +48,13 @@ module RocketJob
|
|
39
48
|
field :run_at, type: Time
|
40
49
|
|
41
50
|
# If a job has not started by this time, destroy it
|
42
|
-
field :expires_at, type: Time
|
51
|
+
field :expires_at, type: Time, copy_on_restart: true
|
43
52
|
|
44
53
|
# Raise or lower the log level when calling the job
|
45
54
|
# Can be used to reduce log noise, especially during high volume calls
|
46
55
|
# For debugging a single job can be logged at a low level such as :trace
|
47
56
|
# Levels supported: :trace, :debug, :info, :warn, :error, :fatal
|
48
|
-
field :log_level, type: Symbol, class_attribute: true, user_editable: true
|
57
|
+
field :log_level, type: Symbol, class_attribute: true, user_editable: true, copy_on_restart: true
|
49
58
|
|
50
59
|
#
|
51
60
|
# Read-only attributes
|
@@ -150,6 +159,40 @@ module RocketJob
|
|
150
159
|
queued.or({:run_at => nil}, {:run_at.lte => Time.now})
|
151
160
|
end
|
152
161
|
|
162
|
+
# Defines all the fields that are accessible on the Document
|
163
|
+
# For each field that is defined, a getter and setter will be
|
164
|
+
# added as an instance method to the Document.
|
165
|
+
#
|
166
|
+
# @example Define a field.
|
167
|
+
# field :score, :type => Integer, :default => 0
|
168
|
+
#
|
169
|
+
# @param [ Symbol ] name The name of the field.
|
170
|
+
# @param [ Hash ] options The options to pass to the field.
|
171
|
+
#
|
172
|
+
# @option options [ Class ] :type The type of the field.
|
173
|
+
# @option options [ String ] :label The label for the field.
|
174
|
+
# @option options [ Object, Proc ] :default The field's default
|
175
|
+
# @option options [ Boolean ] :class_attribute Keep the fields default in a class_attribute
|
176
|
+
# @option options [ Boolean ] :user_editable Field can be edited by end users in RJMC
|
177
|
+
#
|
178
|
+
# @return [ Field ] The generated field
|
179
|
+
def field(name, options)
|
180
|
+
if options.delete(:user_editable) == true
|
181
|
+
self.user_editable_fields += [name.to_sym] unless user_editable_fields.include?(name.to_sym)
|
182
|
+
end
|
183
|
+
if options.delete(:class_attribute) == true
|
184
|
+
class_attribute(name, instance_accessor: false)
|
185
|
+
if options.has_key?(:default)
|
186
|
+
public_send("#{name}=", options[:default])
|
187
|
+
end
|
188
|
+
options[:default] = lambda { self.class.public_send(name) }
|
189
|
+
end
|
190
|
+
if options.delete(:copy_on_restart) == true
|
191
|
+
self.rocket_job_restart_attributes += [name.to_sym] unless rocket_job_restart_attributes.include?(name.to_sym)
|
192
|
+
end
|
193
|
+
super(name, options)
|
194
|
+
end
|
195
|
+
|
153
196
|
# DEPRECATED
|
154
197
|
def rocket_job
|
155
198
|
warn 'Replace calls to .rocket_job with calls to set class instance variables. For example: self.priority = 50'
|
@@ -21,8 +21,9 @@ module RocketJob
|
|
21
21
|
#
|
22
22
|
# # The start of the processing window
|
23
23
|
# self.processing_schedule = "30 8 * * * America/New_York"
|
24
|
+
#
|
24
25
|
# # How long the processing window is:
|
25
|
-
# self
|
26
|
+
# self.processing_duration = 12.hours
|
26
27
|
#
|
27
28
|
# def perform
|
28
29
|
# # Job will only run between 8:30am and 8:30pm Eastern
|
@@ -37,8 +38,8 @@ module RocketJob
|
|
37
38
|
extend ActiveSupport::Concern
|
38
39
|
|
39
40
|
included do
|
40
|
-
field :processing_schedule, type: String, class_attribute: true
|
41
|
-
field :processing_duration, type: Integer, class_attribute: true
|
41
|
+
field :processing_schedule, type: String, class_attribute: true, user_editable: true, copy_on_restart: true
|
42
|
+
field :processing_duration, type: Integer, class_attribute: true, user_editable: true, copy_on_restart: true
|
42
43
|
|
43
44
|
before_create :rocket_job_processing_window_set_run_at
|
44
45
|
before_retry :rocket_job_processing_window_set_run_at
|
@@ -3,49 +3,93 @@ require 'active_support/concern'
|
|
3
3
|
module RocketJob
|
4
4
|
module Plugins
|
5
5
|
# Automatically starts a new instance of this job anytime it fails, aborts, or completes.
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
6
|
+
#
|
7
|
+
# Notes:
|
8
|
+
# * Restartable jobs automatically abort if they fail. This prevents the failed job from being retried.
|
9
|
+
# - To disable this behavior, add the following empty method:
|
10
|
+
# def rocket_job_restart_abort
|
11
|
+
# end
|
12
|
+
# * On destroy this job is destroyed without starting a new instance.
|
13
|
+
# * On Abort a new instance is created.
|
14
|
+
# * Include `RocketJob::Plugins::Singleton` to prevent multiple copies of a job from running at
|
15
|
+
# the same time.
|
16
|
+
# * The job will not be restarted if:
|
17
|
+
# - A validation fails after creating the new instance of this job.
|
15
18
|
# - The job has expired.
|
19
|
+
# * Only the fields that have `copy_on_restart: true` will be passed onto the new instance of this job.
|
20
|
+
#
|
21
|
+
# Example:
|
22
|
+
#
|
23
|
+
# class RestartableJob < RocketJob::Job
|
24
|
+
# include RocketJob::Plugins::Restart
|
25
|
+
#
|
26
|
+
# # Retain the completed job under the completed tab in Rocket Job Mission Control.
|
27
|
+
# self.destroy_on_complete = false
|
28
|
+
#
|
29
|
+
# # Will be copied to the new job on restart.
|
30
|
+
# field :limit, type: Integer, copy_on_restart: true
|
31
|
+
#
|
32
|
+
# # Will _not_ be copied to the new job on restart.
|
33
|
+
# field :list, type: Array, default: [1,2,3]
|
34
|
+
#
|
35
|
+
# # Set run_at every time a new instance of the job is created.
|
36
|
+
# after_initialize set_run_at, if: :new_record?
|
37
|
+
#
|
38
|
+
# def perform
|
39
|
+
# puts "The limit is #{limit}"
|
40
|
+
# puts "The list is #{list}"
|
41
|
+
# 'DONE'
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# private
|
45
|
+
#
|
46
|
+
# # Run this job in 30 minutes.
|
47
|
+
# def set_run_at
|
48
|
+
# self.run_at = 30.minutes.from_now
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# job = RestartableJob.create!(limit: 10, list: [4,5,6])
|
53
|
+
# job.reload.state
|
54
|
+
# # => :queued
|
55
|
+
#
|
56
|
+
# job.limit
|
57
|
+
# # => 10
|
58
|
+
#
|
59
|
+
# job.list
|
60
|
+
# # => [4,5,6]
|
61
|
+
#
|
62
|
+
# # Wait 30 minutes ...
|
63
|
+
#
|
64
|
+
# job.reload.state
|
65
|
+
# # => :completed
|
66
|
+
#
|
67
|
+
# # A new instance was automatically created.
|
68
|
+
# job2 = RestartableJob.last
|
69
|
+
# job2.state
|
70
|
+
# # => :queued
|
71
|
+
#
|
72
|
+
# job2.limit
|
73
|
+
# # => 10
|
74
|
+
#
|
75
|
+
# job2.list
|
76
|
+
# # => [1,2,3]
|
16
77
|
module Restart
|
17
78
|
extend ActiveSupport::Concern
|
18
79
|
|
19
80
|
included do
|
20
|
-
# Attributes to exclude when copying across the attributes to the new instance
|
21
|
-
class_attribute :rocket_job_restart_excludes
|
22
|
-
self.rocket_job_restart_excludes = %w(_id state created_at started_at completed_at failure_count worker_name percent_complete exception result run_at record_count sub_state)
|
23
|
-
|
24
81
|
after_abort :rocket_job_restart_new_instance
|
25
82
|
after_complete :rocket_job_restart_new_instance
|
26
83
|
after_fail :rocket_job_restart_abort
|
27
84
|
end
|
28
85
|
|
29
|
-
module ClassMethods
|
30
|
-
def field(name, options)
|
31
|
-
if options.delete(:copy_on_restart) == false
|
32
|
-
self.rocket_job_restart_excludes += [name.to_sym] unless rocket_job_restart_excludes.include?(name.to_sym)
|
33
|
-
end
|
34
|
-
super(name, options)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
86
|
private
|
39
87
|
|
40
88
|
# Run again in the future, even if this run fails with an exception
|
41
89
|
def rocket_job_restart_new_instance
|
90
|
+
logger.info('Job has expired. Not creating a new instance.')
|
42
91
|
return if expired?
|
43
|
-
attrs =
|
44
|
-
rocket_job_restart_excludes.each { |attr| attrs.delete(attr) }
|
45
|
-
|
46
|
-
# Copy across run_at for future dated jobs
|
47
|
-
attrs['run_at'] = run_at if run_at && (run_at > Time.now)
|
48
|
-
|
92
|
+
attrs = rocket_job_restart_attributes.reduce({}) { |attrs, attr| attrs[attr] = send(attr); attrs }
|
49
93
|
rocket_job_restart_create(attrs)
|
50
94
|
end
|
51
95
|
|
@@ -60,7 +104,7 @@ module RocketJob
|
|
60
104
|
while count < retry_limit
|
61
105
|
job = self.class.create(attrs)
|
62
106
|
if job.persisted?
|
63
|
-
logger.info("
|
107
|
+
logger.info("Created a new job instance: #{job.id}")
|
64
108
|
return true
|
65
109
|
else
|
66
110
|
logger.info('Job already active, retrying after a short sleep')
|
@@ -72,7 +116,6 @@ module RocketJob
|
|
72
116
|
false
|
73
117
|
end
|
74
118
|
|
75
|
-
|
76
119
|
end
|
77
120
|
end
|
78
121
|
end
|
@@ -49,7 +49,7 @@ 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 :max_retries, type: Integer, default: 25, class_attribute: true, user_editable: true
|
52
|
+
field :max_retries, 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
55
|
field :failed_times, type: Array, default: []
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RocketJob
|
2
|
+
# Whether the current process is running inside a Rocket Job server process.
|
3
|
+
def self.server?
|
4
|
+
server
|
5
|
+
end
|
6
|
+
|
7
|
+
# When running inside a Rocket Job server process, returns
|
8
|
+
# true when Rails has been initialized.
|
9
|
+
def self.rails?
|
10
|
+
rails
|
11
|
+
end
|
12
|
+
|
13
|
+
# When running inside a Rocket Job server process, returns
|
14
|
+
# true when running standalone.
|
15
|
+
def self.standalone?
|
16
|
+
!rails
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a human readable duration from the supplied [Float] number of seconds
|
20
|
+
def self.seconds_as_duration(seconds)
|
21
|
+
return nil unless seconds
|
22
|
+
if seconds >= 86400.0 # 1 day
|
23
|
+
"#{(seconds / 86400).to_i}d #{Time.at(seconds).strftime('%-Hh %-Mm')}"
|
24
|
+
elsif seconds >= 3600.0 # 1 hour
|
25
|
+
Time.at(seconds).strftime('%-Hh %-Mm')
|
26
|
+
elsif seconds >= 60.0 # 1 minute
|
27
|
+
Time.at(seconds).strftime('%-Mm %-Ss')
|
28
|
+
elsif seconds >= 1.0 # 1 second
|
29
|
+
"#{'%.3f' % seconds}s"
|
30
|
+
else
|
31
|
+
duration = seconds * 1000
|
32
|
+
if defined? JRuby
|
33
|
+
"#{duration.to_i}ms"
|
34
|
+
else
|
35
|
+
duration < 10.0 ? "#{'%.3f' % duration}ms" : "#{'%.1f' % duration}ms"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# private
|
41
|
+
|
42
|
+
@rails = false
|
43
|
+
@server = false
|
44
|
+
|
45
|
+
def self.server!
|
46
|
+
@server = true
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.rails!
|
50
|
+
@rails = true
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/lib/rocket_job/version.rb
CHANGED
data/lib/rocket_job/worker.rb
CHANGED
@@ -102,7 +102,7 @@ module RocketJob
|
|
102
102
|
job = Job.rocket_job_next_job(name, current_filter)
|
103
103
|
break unless job
|
104
104
|
|
105
|
-
|
105
|
+
SemanticLogger.named_tagged(job: job.id.to_s) do
|
106
106
|
unless job.rocket_job_work(self, false, current_filter)
|
107
107
|
processed = true
|
108
108
|
end
|
data/lib/rocketjob.rb
CHANGED
@@ -2,6 +2,7 @@ require 'semantic_logger'
|
|
2
2
|
require 'mongoid'
|
3
3
|
require 'rocket_job/extensions/mongo/logging'
|
4
4
|
require 'rocket_job/version'
|
5
|
+
require 'rocket_job/rocket_job'
|
5
6
|
|
6
7
|
# @formatter:off
|
7
8
|
module RocketJob
|
@@ -41,33 +42,11 @@ module RocketJob
|
|
41
42
|
end
|
42
43
|
|
43
44
|
module Jobs
|
45
|
+
autoload :ActiveJob, 'rocket_job/jobs/active_job'
|
44
46
|
autoload :DirmonJob, 'rocket_job/jobs/dirmon_job'
|
45
47
|
autoload :HousekeepingJob, 'rocket_job/jobs/housekeeping_job'
|
46
48
|
autoload :SimpleJob, 'rocket_job/jobs/simple_job'
|
47
49
|
end
|
48
|
-
|
49
|
-
# @formatter:on
|
50
|
-
# Returns a human readable duration from the supplied [Float] number of seconds
|
51
|
-
def self.seconds_as_duration(seconds)
|
52
|
-
return nil unless seconds
|
53
|
-
if seconds >= 86400.0 # 1 day
|
54
|
-
"#{(seconds / 86400).to_i}d #{Time.at(seconds).strftime('%-Hh %-Mm')}"
|
55
|
-
elsif seconds >= 3600.0 # 1 hour
|
56
|
-
Time.at(seconds).strftime('%-Hh %-Mm')
|
57
|
-
elsif seconds >= 60.0 # 1 minute
|
58
|
-
Time.at(seconds).strftime('%-Mm %-Ss')
|
59
|
-
elsif seconds >= 1.0 # 1 second
|
60
|
-
"#{'%.3f' % seconds}s"
|
61
|
-
else
|
62
|
-
duration = seconds * 1000
|
63
|
-
if defined? JRuby
|
64
|
-
"#{duration.to_i}ms"
|
65
|
-
else
|
66
|
-
duration < 10.0 ? "#{'%.3f' % duration}ms" : "#{'%.1f' % duration}ms"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
50
|
end
|
72
51
|
|
73
52
|
# Add Active Job adapter for Rails
|
@@ -6,9 +6,6 @@ module Plugins
|
|
6
6
|
class RestartableJob < RocketJob::Job
|
7
7
|
include RocketJob::Plugins::Restart
|
8
8
|
|
9
|
-
# Ensure a new start_at and end_at is generated every time this job is restarted
|
10
|
-
self.rocket_job_restart_excludes += %w(start_at end_at)
|
11
|
-
|
12
9
|
field :start_at, type: Date
|
13
10
|
field :end_at, type: Date
|
14
11
|
|
@@ -153,11 +150,14 @@ module Plugins
|
|
153
150
|
assert job2 = RestartableJob.where(:id.ne => @job.id).first
|
154
151
|
assert job2.queued?, job2.attributes.ai
|
155
152
|
|
153
|
+
assert RestartableJob.rocket_job_restart_attributes.include?(:priority)
|
154
|
+
assert RestartableJob.rocket_job_restart_attributes.exclude?(:start_at)
|
155
|
+
assert RestartableJob.rocket_job_restart_attributes.exclude?(:end_at)
|
156
|
+
assert RestartableJob.rocket_job_restart_attributes.exclude?(:run_at)
|
157
|
+
|
156
158
|
# Copy across all attributes, except
|
157
|
-
|
158
|
-
|
159
|
-
next if RestartableJob.rocket_job_restart_excludes.include?(key)
|
160
|
-
assert_equal value, job2[key], "Attributes are supposed to be copied across. For #{key}"
|
159
|
+
RestartableJob.rocket_job_restart_attributes.each do |key|
|
160
|
+
assert_equal @job.send(key).to_s, job2.send(key).to_s, "Attributes are supposed to be copied across. For #{key}"
|
161
161
|
end
|
162
162
|
|
163
163
|
assert_nil job2.start_at
|
@@ -172,22 +172,6 @@ module Plugins
|
|
172
172
|
assert_nil job2.exception
|
173
173
|
refute job2.result
|
174
174
|
end
|
175
|
-
|
176
|
-
it 'copies run_at when it is in the future' do
|
177
|
-
@job = RestartableJob.create!(run_at: Time.now + 1.day, destroy_on_complete: true)
|
178
|
-
@job.perform_now
|
179
|
-
assert_equal 1, RestartableJob.count
|
180
|
-
assert job2 = RestartableJob.where(:id.ne => @job.id).first
|
181
|
-
assert job2.run_at, job2.attributes.ai
|
182
|
-
end
|
183
|
-
|
184
|
-
it 'does not copy run_at when it is in the past' do
|
185
|
-
@job = RestartableJob.create!(run_at: Time.now - 1.day, destroy_on_complete: true)
|
186
|
-
@job.perform_now
|
187
|
-
assert_equal 1, RestartableJob.count
|
188
|
-
assert job2 = RestartableJob.where(:id.ne => @job.id).first
|
189
|
-
assert_nil job2.run_at
|
190
|
-
end
|
191
175
|
end
|
192
176
|
|
193
177
|
end
|
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.
|
4
|
+
version: 3.2.0
|
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-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -89,6 +89,7 @@ files:
|
|
89
89
|
- lib/rocket_job/heartbeat.rb
|
90
90
|
- lib/rocket_job/job.rb
|
91
91
|
- lib/rocket_job/job_exception.rb
|
92
|
+
- lib/rocket_job/jobs/active_job.rb
|
92
93
|
- lib/rocket_job/jobs/dirmon_job.rb
|
93
94
|
- lib/rocket_job/jobs/housekeeping_job.rb
|
94
95
|
- lib/rocket_job/jobs/simple_job.rb
|
@@ -110,6 +111,7 @@ files:
|
|
110
111
|
- lib/rocket_job/plugins/rufus/zo_time.rb
|
111
112
|
- lib/rocket_job/plugins/singleton.rb
|
112
113
|
- lib/rocket_job/plugins/state_machine.rb
|
114
|
+
- lib/rocket_job/rocket_job.rb
|
113
115
|
- lib/rocket_job/server.rb
|
114
116
|
- lib/rocket_job/version.rb
|
115
117
|
- lib/rocket_job/worker.rb
|