rocketjob 3.0.0.beta2 → 3.0.0.beta3

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 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