rocketjob 3.0.0.beta2 → 3.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8e79fbd2ab361a944bd653f0f8f614aa0cb8f951
4
- data.tar.gz: 79b67d6410a552e521dd89964103fef4400c4dee
3
+ metadata.gz: 2893cad7faa49cc61dc42a18e1769b7e4b0684cd
4
+ data.tar.gz: 0484cd6616b0d1dbef6ecd67d0235ef0d3834623
5
5
  SHA512:
6
- metadata.gz: 54c2021c45ace9f90b646db94edbe54863f70b9eb6397bc6f8204842422cbc22b287c3d685397a219f53dd462b388d589dd7dbb28af6b2add95894c4cd8029f5
7
- data.tar.gz: c5e18971e9c434ea64901dfe377cea4ea92685ef9d1b9c445bc37a3f43830edf15ae42e4edf23bb481576fb9557f420136d1617c48603ef75a962c406ede9986
6
+ metadata.gz: 13e4e156847cfebb938b7700eaddda5899b79f816d690b3555d77aa6b993cc046e76c6b796404e83f3767ce482a4db50134a7037a6e7ba3ea9fd85b296834689
7
+ data.tar.gz: 60856f69ce93c2c0143cbf349f8c9eb393c038e44897d3f1ab16c550cec10557656628892d92ce6fbc833c5353f7b4a936a790932c219b9df7c8384cdd6f360d
@@ -4,7 +4,9 @@ module RocketJob
4
4
  # Command Line Interface parser for RocketJob
5
5
  class CLI
6
6
  include SemanticLogger::Loggable
7
- attr_accessor :name, :workers, :environment, :pidfile, :directory, :quiet, :log_level, :log_file, :mongo_config, :symmetric_encryption_config
7
+ attr_accessor :name, :workers, :environment, :pidfile, :directory, :quiet,
8
+ :log_level, :log_file, :mongo_config, :symmetric_encryption_config,
9
+ :filter
8
10
 
9
11
  def initialize(argv)
10
12
  @name = nil
@@ -17,6 +19,7 @@ module RocketJob
17
19
  @log_file = nil
18
20
  @mongo_config = nil
19
21
  @symmetric_encryption_config = nil
22
+ @filter = nil
20
23
  parse(argv)
21
24
  end
22
25
 
@@ -31,6 +34,7 @@ module RocketJob
31
34
  opts = {}
32
35
  opts[:name] = name if name
33
36
  opts[:max_workers] = workers if workers
37
+ opts[:filter] = {:_type => filter} if filter
34
38
  Server.run(opts)
35
39
  end
36
40
 
@@ -142,6 +146,9 @@ module RocketJob
142
146
  warn '-t and --threads are deprecated, use -w or --workers'
143
147
  @workers = arg.to_i
144
148
  end
149
+ o.on('-F', '--filter REGEXP', 'Limit this worker to only those job classes that match this regular expression (case-insensitive)') do |arg|
150
+ @filter = Regexp.new(arg, true)
151
+ end
145
152
  o.on('-q', '--quiet', 'Do not write to stdout, only to logfile. Necessary when running as a daemon') do
146
153
  @quiet = true
147
154
  end
@@ -21,6 +21,8 @@ module RocketJob
21
21
  # Also, exceptions will be raised instead of failing the job.
22
22
  cattr_accessor(:inline_mode) { false }
23
23
 
24
+ store_in collection: 'rocket_job.configs'
25
+
24
26
  #
25
27
  # Servers
26
28
  #
@@ -6,6 +6,8 @@ module RocketJob
6
6
  include Plugins::Document
7
7
  include Plugins::StateMachine
8
8
 
9
+ store_in collection: 'rocket_job.dirmon_entries'
10
+
9
11
  # User defined name used to identify this DirmonEntry in Mission Control
10
12
  field :name, type: String
11
13
 
@@ -11,5 +11,6 @@ module RocketJob
11
11
  include Plugins::StateMachine
12
12
  include Plugins::Job::StateMachine
13
13
  include Plugins::Job::Worker
14
+ include Plugins::Job::Throttle
14
15
  end
15
16
  end
@@ -2,41 +2,49 @@ require 'csv'
2
2
  require 'yaml'
3
3
  module RocketJob
4
4
  class Performance
5
- attr_accessor :count, :worker_processes, :worker_threads, :version, :ruby, :environment, :mongo_config
5
+ attr_accessor :count, :servers, :workers, :version, :ruby, :environment, :mongo_config
6
6
 
7
7
  def initialize
8
- @version = RocketJob::VERSION
9
- @ruby = defined?(JRuby) ? "jruby_#{JRUBY_VERSION}" : "ruby_#{RUBY_VERSION}"
10
- @count = 100_000
11
- @worker_processes = 0
12
- @worker_threads = 0
13
- @environment = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
14
- @mongo_config = 'config/mongo.yml'
8
+ @version = RocketJob::VERSION
9
+ @ruby = defined?(JRuby) ? "jruby_#{JRUBY_VERSION}" : "ruby_#{RUBY_VERSION}"
10
+ @count = 100_000
11
+ @servers = 0
12
+ @workers = 0
13
+ @environment = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
14
+ @mongo_config = 'config/mongoid.yml'
15
15
  end
16
16
 
17
17
  def run_test_case(count = self.count)
18
- self.worker_processes = RocketJob::Server.count
19
- raise 'Please start workers before starting the performance test' if worker_processes == 0
18
+ raise 'Please start servers before starting the performance test' if RocketJob::Server.where(:state.in => ['running', 'paused']).count == 0
20
19
 
21
- self.worker_processes = 0
22
- self.worker_threads = 0
23
- RocketJob::Server.running.each do |worker_process|
24
- unless worker_process.zombie?
25
- self.worker_processes += 1
26
- self.worker_threads += worker_process.heartbeat.workers
27
- end
20
+ self.servers = 0
21
+ self.workers = 0
22
+ RocketJob::Server.running.each do |server|
23
+ next if server.zombie?
24
+ self.servers += 1
25
+ self.workers += server.heartbeat.workers
28
26
  end
29
- puts "Running: #{worker_threads} workers, distributed across #{worker_processes} processes"
27
+ puts "Running: #{workers} workers, distributed across #{servers} servers"
30
28
 
31
29
  puts 'Waiting for workers to pause'
32
30
  RocketJob::Server.pause_all
33
31
  RocketJob::Jobs::SimpleJob.delete_all
34
- sleep 15
32
+
33
+ # Wait for paused workers to stop
34
+ loop do
35
+ running = 0
36
+ RocketJob::Server.paused.each do |server|
37
+ running += server.heartbeat.workers unless server.zombie?
38
+ end
39
+ puts "Waiting for #{running} workers"
40
+ break if running == 0
41
+ sleep 1
42
+ end
35
43
 
36
44
  puts 'Enqueuing jobs'
37
- first = RocketJob::Jobs::SimpleJob.create(priority: 1, destroy_on_complete: false)
45
+ first = RocketJob::Jobs::SimpleJob.create!(priority: 1, destroy_on_complete: false)
38
46
  (count - 2).times { |i| RocketJob::Jobs::SimpleJob.create! }
39
- last = RocketJob::Jobs::SimpleJob.create(priority: 100, destroy_on_complete: false)
47
+ last = RocketJob::Jobs::SimpleJob.create!(priority: 100, destroy_on_complete: false)
40
48
 
41
49
  puts 'Resuming workers'
42
50
  RocketJob::Server.resume_all
@@ -51,7 +59,7 @@ module RocketJob
51
59
 
52
60
  # Export the Results hash to a CSV file
53
61
  def export_results(results)
54
- CSV.open("job_results_#{ruby}_#{worker_processes}p_#{threads}t_v#{version}.csv", 'wb') do |csv|
62
+ CSV.open("job_results_#{ruby}_#{servers}s_#{workers}w_v#{version}.csv", 'wb') do |csv|
55
63
  csv << results.first.keys
56
64
  results.each { |result| csv << result.values }
57
65
  end
@@ -148,11 +148,7 @@ module RocketJob
148
148
  # Scope for queued jobs that can run now
149
149
  # I.e. Queued jobs excluding scheduled jobs
150
150
  def queued_now
151
- queued.or(
152
- {:run_at.exists => false},
153
- {:run_at => nil},
154
- {:run_at.lte => Time.now}
155
- )
151
+ queued.or({:run_at => nil}, {:run_at.lte => Time.now})
156
152
  end
157
153
 
158
154
  # DEPRECATED
@@ -12,24 +12,34 @@ module RocketJob
12
12
  # Store all job types in this collection
13
13
  store_in collection: 'rocket_job.jobs'
14
14
 
15
+ after_initialize :remove_arguments
16
+ end
17
+
18
+ module ClassMethods
15
19
  # Retrieves the next job to work on in priority based order
16
20
  # and assigns it to this worker
17
21
  #
18
22
  # Returns nil if no jobs are available for processing
19
23
  #
20
24
  # Parameters
21
- # worker_name [String]
25
+ # worker_name: [String]
22
26
  # Name of the worker that will be processing this job
23
27
  #
24
- # skip_job_ids [Array<BSON::ObjectId>]
25
- # Job ids to exclude when looking for the next job
26
- def self.rocket_job_retrieve(worker_name, skip_job_ids = nil)
27
- query = queued_now
28
- update = {'$set' => {'worker_name' => worker_name, 'state' => 'running', 'started_at' => Time.now}}
29
-
30
- query = query.where(:id.nin => skip_job_ids) if skip_job_ids && skip_job_ids.size > 0
31
-
32
- query.sort(priority: 1, _id: 1).find_one_and_update(update)
28
+ # filter: [Hash]
29
+ # Filter to apply to the query.
30
+ # For example: to exclude jobs from being returned.
31
+ #
32
+ # Example:
33
+ # # Skip any job ids from the job_ids_list
34
+ # filter = {:id.nin => job_ids_list}
35
+ # job = RocketJob::Job.rocket_job_retrieve('host:pid:worker', filter)
36
+ def rocket_job_retrieve(worker_name, filter)
37
+ SemanticLogger.silence(:info) do
38
+ query = queued_now
39
+ query = query.where(filter) unless filter.blank?
40
+ update = {'$set' => {'worker_name' => worker_name, 'state' => 'running', 'started_at' => Time.now}}
41
+ query.sort(priority: 1, _id: 1).find_one_and_update(update, bypass_document_validation: true)
42
+ end
33
43
  end
34
44
 
35
45
  # Returns [Hash<String:Integer>] of the number of jobs in each state
@@ -59,7 +69,7 @@ module RocketJob
59
69
  # :running => 25,
60
70
  # :completed => 1237
61
71
  # }
62
- def self.counts_by_state
72
+ def counts_by_state
63
73
  counts = {}
64
74
  collection.aggregate([
65
75
  {
@@ -86,7 +96,6 @@ module RocketJob
86
96
  end
87
97
  counts
88
98
  end
89
-
90
99
  end
91
100
 
92
101
  # Set in-memory job to complete if `destroy_on_complete` and the job has been destroyed
@@ -104,6 +113,13 @@ module RocketJob
104
113
  end
105
114
  end
106
115
 
116
+ private
117
+
118
+ # Remove old style arguments that were stored as an array
119
+ def remove_arguments
120
+ attributes.delete('arguments') unless respond_to?('arguments='.to_sym)
121
+ end
122
+
107
123
  end
108
124
  end
109
125
  end
@@ -0,0 +1,75 @@
1
+ # encoding: UTF-8
2
+ require 'active_support/concern'
3
+
4
+ module RocketJob
5
+ module Plugins
6
+ module Job
7
+ # Throttle number of jobs of a specific class that are processed at the same time.
8
+ #
9
+ # Example:
10
+ # class MyJob < RocketJob
11
+ # # Maximum number of workers to process instances of this job at the same time.
12
+ # self.throttle_max_workers = 25
13
+ #
14
+ # def perform
15
+ # # ....
16
+ # end
17
+ # end
18
+ #
19
+ # Notes:
20
+ # - The actual number will be around this value, it con go over slightly and
21
+ # can drop depending on check interval can drop slightly below this value.
22
+ # - By avoid hard locks and counters performance can be maintained while still
23
+ # supporting good enough throttling.
24
+ # - If throughput is not as important as preventing brief spikes when many
25
+ # workers are running, add a double check into the perform:
26
+ # class MyJob < RocketJob
27
+ # self.throttle_max_workers = 25
28
+ #
29
+ # def perform
30
+ # # (Optional) Prevent a brief spike from exceeding the wax worker throttle
31
+ # self.class.throttle_double_check
32
+ #
33
+ # # ....
34
+ # end
35
+ # end
36
+ module Throttle
37
+ extend ActiveSupport::Concern
38
+
39
+ included do
40
+ class_attribute :throttle_max_workers
41
+ self.throttle_max_workers = nil
42
+ end
43
+
44
+ # Throttle to add when the throttle is exceeded
45
+ def throttle_filter
46
+ {:_type.nin => self.class.name}
47
+ end
48
+
49
+ # Returns [Boolean] whether the throttle for this job has been exceeded
50
+ def throttle_exceeded?
51
+ throttle_max_workers && (throttle_max_workers != 0) ? (self.class.running.count >= throttle_max_workers) : false
52
+ end
53
+
54
+ # Prevent a brief spike from exceeding the wax worker throttle
55
+ def throttle_double_check(check_seconds = 1)
56
+ while !throttle_exceeded?
57
+ sleep check_seconds
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ # Merge filter(s)
64
+ def throttle_merge_filter(target, source)
65
+ source.each_key do |k, v|
66
+ previous = target[k]
67
+ target[k] = previous ? (Array(previous) << v) : v
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -48,8 +48,8 @@ module RocketJob
48
48
  #
49
49
  # Note:
50
50
  # If a job is in queued state it will be started
51
- def rocket_job_next_job(worker_name, skip_job_ids = nil)
52
- while (job = rocket_job_retrieve(worker_name, skip_job_ids))
51
+ def rocket_job_next_job(worker_name, filter = {})
52
+ while (job = rocket_job_retrieve(worker_name, filter))
53
53
  case
54
54
  when job.running?
55
55
  # Batch Job
@@ -57,6 +57,11 @@ module RocketJob
57
57
  when job.expired?
58
58
  job.rocket_job_fail_on_exception!(worker_name) { job.destroy }
59
59
  logger.info "Destroyed expired job #{job.class.name}, id:#{job.id}"
60
+ when job.throttle_exceeded?
61
+ # Add jobs filter to the current filter
62
+ throttle_merge_filter(filter, job.throttle_filter)
63
+ # Restore retrieved job so that other workers can process it later
64
+ job.set(worker_name: nil, state: :queued)
60
65
  else
61
66
  job.worker_name = worker_name
62
67
  job.rocket_job_fail_on_exception!(worker_name) do
@@ -70,7 +75,7 @@ module RocketJob
70
75
  # Requeues all jobs that were running on a server that died
71
76
  def requeue_dead_server(server_name)
72
77
  # Need to requeue paused, failed since user may have transitioned job before it finished
73
- where(:state.in => [:running, :paused, :faled]).each do |job|
78
+ where(:state.in => [:running, :paused, :failed]).each do |job|
74
79
  job.requeue!(server_name) if job.may_requeue?(server_name)
75
80
  end
76
81
  end
@@ -136,19 +141,24 @@ module RocketJob
136
141
  # is set in the job itself.
137
142
  #
138
143
  # Thread-safe, can be called by multiple threads at the same time
139
- def rocket_job_work(worker, re_raise_exceptions = false)
144
+ def rocket_job_work(worker, re_raise_exceptions = false, filter = nil)
140
145
  raise(ArgumentError, 'Job must be started before calling #rocket_job_work') unless running?
141
146
  rocket_job_fail_on_exception!(worker.name, re_raise_exceptions) do
142
- run_callbacks :perform do
143
- # Allow callbacks to fail, complete or abort the job
144
- if running?
145
- ret = perform
146
- if collect_output?
147
- # Result must be a Hash, if not put it in a Hash
148
- self.result = ret.is_a?(Hash) ? ret : {'result' => ret}
149
- end
147
+ if _perform_callbacks.empty?
148
+ @rocket_job_output = perform
149
+ else
150
+ # Allows @rocket_job_output to be modified by after/around callbacks
151
+ run_callbacks(:perform) do
152
+ # Allow callbacks to fail, complete or abort the job
153
+ @rocket_job_output = perform if running?
150
154
  end
151
155
  end
156
+
157
+ if collect_output?
158
+ # Result must be a Hash, if not put it in a Hash
159
+ self.result = @rocket_job_output.is_a?(Hash) ? @rocket_job_output : {'result' => @rocket_job_output}
160
+ end
161
+
152
162
  if new_record? || destroyed?
153
163
  complete if may_complete?
154
164
  else
@@ -30,6 +30,8 @@ module RocketJob
30
30
  include Plugins::StateMachine
31
31
  include SemanticLogger::Loggable
32
32
 
33
+ store_in collection: 'rocket_job.servers'
34
+
33
35
  # Unique Name of this server instance
34
36
  # Default: `host name:PID`
35
37
  # The unique name is used on re-start to re-queue any jobs that were being processed
@@ -43,6 +45,9 @@ module RocketJob
43
45
  # When this server process was started
44
46
  field :started_at, type: Time
45
47
 
48
+ # Filter to apply to control which job classes this server can process
49
+ field :filter, type: Hash
50
+
46
51
  # The heartbeat information for this server
47
52
  embeds_one :heartbeat, class_name: 'RocketJob::Heartbeat'
48
53
 
@@ -188,7 +193,6 @@ module RocketJob
188
193
 
189
194
  server = create!(attrs)
190
195
  server.send(:run)
191
-
192
196
  ensure
193
197
  server.destroy if server
194
198
  end
@@ -225,22 +229,31 @@ module RocketJob
225
229
  logger.info "Using MongoDB Database: #{RocketJob::Job.collection.database.name}"
226
230
  build_heartbeat(updated_at: Time.now, workers: 0)
227
231
  started!
228
- adjust_workers(true)
229
- logger.info "RocketJob Server started with #{workers.size} workers running"
232
+ logger.info 'RocketJob Server started'
230
233
 
234
+ stagger = true
231
235
  while running? || paused?
232
- sleep Config.instance.heartbeat_seconds
233
-
234
- find_and_update(
235
- 'heartbeat.updated_at' => Time.now,
236
- 'heartbeat.workers' => worker_count
237
- )
236
+ SemanticLogger.silence(:info) do
237
+ find_and_update(
238
+ 'heartbeat.updated_at' => Time.now,
239
+ 'heartbeat.workers' => worker_count
240
+ )
241
+ end
242
+ if paused?
243
+ workers.each(&:shutdown!)
244
+ stagger = true
245
+ end
238
246
 
239
247
  # In case number of threads has been modified
240
- adjust_workers
248
+ adjust_workers(stagger)
249
+ stagger = false
241
250
 
242
251
  # Stop server if shutdown indicator was set
243
- stop! if self.class.shutdown? && may_stop?
252
+ if self.class.shutdown? && may_stop?
253
+ stop!
254
+ else
255
+ sleep Config.instance.heartbeat_seconds
256
+ end
244
257
  end
245
258
 
246
259
  logger.info 'Waiting for workers to stop'
@@ -293,7 +306,7 @@ module RocketJob
293
306
  # that not all workers poll at the same time
294
307
  # The worker also respond faster than max_poll_seconds when a new
295
308
  # job is added.
296
- def adjust_workers(stagger_workers=false)
309
+ def adjust_workers(stagger_workers = false)
297
310
  count = worker_count
298
311
  # Cleanup workers that have stopped
299
312
  if count != workers.count
@@ -301,6 +314,8 @@ module RocketJob
301
314
  workers.delete_if { |t| !t.alive? }
302
315
  end
303
316
 
317
+ return unless running?
318
+
304
319
  # Need to add more workers?
305
320
  if count < max_workers
306
321
  worker_count = max_workers - count
@@ -310,7 +325,7 @@ module RocketJob
310
325
  return if shutdown?
311
326
  # Start worker
312
327
  begin
313
- workers << Worker.new(id: next_worker_id, server_name: name)
328
+ workers << Worker.new(id: next_worker_id, server_name: name, filter: filter)
314
329
  rescue Exception => exc
315
330
  logger.fatal('Cannot start worker', exc)
316
331
  end
@@ -1,4 +1,4 @@
1
1
  # encoding: UTF-8
2
2
  module RocketJob #:nodoc
3
- VERSION = '3.0.0.beta2'
3
+ VERSION = '3.0.0.beta3'
4
4
  end
@@ -17,7 +17,7 @@ module RocketJob
17
17
 
18
18
  define_callbacks :running
19
19
 
20
- attr_accessor :id, :worker_name, :inline
20
+ attr_accessor :id, :re_check_seconds, :filter, :current_filter
21
21
  attr_reader :thread, :name
22
22
 
23
23
  def self.before_running(*filters, &blk)
@@ -32,7 +32,7 @@ module RocketJob
32
32
  set_callback(:running, :around, *filters, &blk)
33
33
  end
34
34
 
35
- def initialize(id: 0, server_name: 'inline', inline: false)
35
+ def initialize(id: 0, server_name: 'inline', inline: false, re_check_seconds: Config.instance.re_check_seconds, filter: nil)
36
36
  @id = id
37
37
  @server_name = server_name
38
38
  if defined?(Concurrent::JavaAtomicBoolean) || defined?(Concurrent::CAtomicBoolean)
@@ -40,8 +40,12 @@ module RocketJob
40
40
  else
41
41
  @shutdown = false
42
42
  end
43
- @name = "#{server_name}:#{id}"
44
- @thread = Thread.new { run } unless inline
43
+ @name = "#{server_name}:#{id}"
44
+ @thread = Thread.new { run } unless inline
45
+ @re_check_seconds = re_check_seconds
46
+ @re_check_start = Time.now
47
+ @filter = filter || {}
48
+ @current_filter = @filter.dup
45
49
  end
46
50
 
47
51
  if defined?(Concurrent::JavaAtomicBoolean) || defined?(Concurrent::CAtomicBoolean)
@@ -87,21 +91,23 @@ module RocketJob
87
91
  rescue Exception => exc
88
92
  logger.fatal('Unhandled exception in job processing thread', exc)
89
93
  ensure
90
- # TODO: Move to after_running callback
91
94
  ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
92
95
  end
93
96
 
94
97
  # Process the next available job
95
98
  # Returns [Boolean] whether any job was actually processed
96
99
  def process_available_jobs
97
- skip_job_ids = []
98
- processed = false
99
- while (job = Job.rocket_job_next_job(worker_name, skip_job_ids)) && !shutdown?
100
+ # Only clear out the current_filter after every `re_check_seconds`
101
+ time = Time.now
102
+ if (time - @re_check_start) > re_check_seconds
103
+ @recheck_start = time
104
+ self.current_filter = filter.dup
105
+ end
106
+
107
+ processed = false
108
+ while (job = Job.rocket_job_next_job(name, current_filter)) && !shutdown?
100
109
  logger.fast_tag("job:#{job.id}") do
101
- if job.rocket_job_work(self)
102
- # Need to skip the specified job due to throttling or no work available
103
- skip_job_ids << job.id
104
- else
110
+ unless job.rocket_job_work(self, false, current_filter)
105
111
  processed = true
106
112
  end
107
113
  end
@@ -25,6 +25,7 @@ module RocketJob
25
25
  autoload :Logger, 'rocket_job/plugins/job/logger'
26
26
  autoload :Model, 'rocket_job/plugins/job/model'
27
27
  autoload :Persistence, 'rocket_job/plugins/job/persistence'
28
+ autoload :Throttle, 'rocket_job/plugins/job/throttle'
28
29
  autoload :Worker, 'rocket_job/plugins/job/worker'
29
30
  end
30
31
  module Rufus
@@ -0,0 +1,56 @@
1
+ require_relative '../../test_helper'
2
+
3
+ # Unit Test for RocketJob::Job
4
+ module Plugins
5
+ module Job
6
+ class ThrottleTest < Minitest::Test
7
+
8
+ class ThrottleJob < RocketJob::Job
9
+ # Only allow one to be processed at a time
10
+ self.throttle_max_workers = 1
11
+
12
+ def perform
13
+ 21
14
+ end
15
+ end
16
+
17
+ describe RocketJob::Plugins::Job::Logger do
18
+ before do
19
+ ThrottleJob.delete_all
20
+ end
21
+
22
+ describe '#throttle_exceeded?' do
23
+ it 'does not exceed throttle when no other jobs are running' do
24
+ ThrottleJob.create!
25
+ job = ThrottleJob.new
26
+ refute job.throttle_exceeded?
27
+ end
28
+
29
+ it 'exceeds throttle when other jobs are running' do
30
+ job1 = ThrottleJob.new
31
+ job1.start!
32
+ job2 = ThrottleJob.new
33
+ assert job2.throttle_exceeded?
34
+ end
35
+
36
+ it 'excludes paused jobs' do
37
+ job1 = ThrottleJob.new
38
+ job1.start
39
+ job1.pause!
40
+ job2 = ThrottleJob.new
41
+ refute job2.throttle_exceeded?
42
+ end
43
+
44
+ it 'excludes failed jobs' do
45
+ job1 = ThrottleJob.new
46
+ job1.start
47
+ job1.fail!
48
+ job2 = ThrottleJob.new
49
+ refute job2.throttle_exceeded?
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+ 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.0.0.beta2
4
+ version: 3.0.0.beta3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-14 00:00:00.000000000 Z
11
+ date: 2016-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -101,6 +101,7 @@ files:
101
101
  - lib/rocket_job/plugins/job/model.rb
102
102
  - lib/rocket_job/plugins/job/persistence.rb
103
103
  - lib/rocket_job/plugins/job/state_machine.rb
104
+ - lib/rocket_job/plugins/job/throttle.rb
104
105
  - lib/rocket_job/plugins/job/worker.rb
105
106
  - lib/rocket_job/plugins/processing_window.rb
106
107
  - lib/rocket_job/plugins/restart.rb
@@ -127,6 +128,7 @@ files:
127
128
  - test/plugins/job/model_test.rb
128
129
  - test/plugins/job/persistence_test.rb
129
130
  - test/plugins/job/state_machine_test.rb
131
+ - test/plugins/job/throttle_test.rb
130
132
  - test/plugins/job/worker_test.rb
131
133
  - test/plugins/processing_window_test.rb
132
134
  - test/plugins/restart_test.rb
@@ -173,6 +175,7 @@ test_files:
173
175
  - test/plugins/job/model_test.rb
174
176
  - test/plugins/job/persistence_test.rb
175
177
  - test/plugins/job/state_machine_test.rb
178
+ - test/plugins/job/throttle_test.rb
176
179
  - test/plugins/job/worker_test.rb
177
180
  - test/plugins/processing_window_test.rb
178
181
  - test/plugins/restart_test.rb