rocketjob 2.0.0 → 2.1.1

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: 3bf52fdcaa423858a798fdd0da28cf9df7448170
4
- data.tar.gz: a8cd888f37215dbe633dad2f13941e629c6463dc
3
+ metadata.gz: eca6d0b99611683528bcec8d6db9756b1bb765a4
4
+ data.tar.gz: 2351fdabe936b770404e0c82d9a052579fac8ae4
5
5
  SHA512:
6
- metadata.gz: 99b6ff7af94d554ff2107deaaade0b639703cf29cd714fcdbe0763f1e4217ae8b22e87a790fd87101a849d1172684a670fb2c6b80c6ec5689ca3991795a0bb53
7
- data.tar.gz: 1d477d2acc562df2a16ebccf500e71d77c570feb486c38a01f8bdcabacc99ebcdf56394b05049b893b5237754633920643c8e8387058666bc0f710984f9058f1
6
+ metadata.gz: 0fa9812d3413bd0dfb18dfe66d61e1f22e538d743030ed3e02d060d74e141e7128bada92fd8c4b24fea1305fcb99b5acfc70172cd5ffb3a309b20c9a6c39802d
7
+ data.tar.gz: 14a209e63e6abc3e491fb51da5760cd3df85bb37e5a12bed758630ecbac5ffe156f78ae22a00028591033a5ac29e5cc22f88c4d117844558f34f9d179442538c
data/README.md CHANGED
@@ -1,13 +1,7 @@
1
1
  # Rocket Job
2
- [![Gem Version](https://img.shields.io/gem/v/rocketjob.svg)](https://rubygems.org/gems/rocketjob) [![Build Status](https://travis-ci.org/rocketjob/rocketjob.svg?branch=master)](https://travis-ci.org/rocketjob/rocketjob) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg) [![Gitter chat](https://img.shields.io/badge/IRC%20(gitter)-Support-brightgreen.svg)](https://gitter.im/rocketjob/support)
2
+ [![Gem Version](https://img.shields.io/gem/v/rocketjob.svg)](https://rubygems.org/gems/rocketjob) [![Build Status](https://travis-ci.org/rocketjob/rocketjob.svg?branch=master)](https://travis-ci.org/rocketjob/rocketjob) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg) [![Support](https://img.shields.io/badge/IRC%20(gitter)-Support-brightgreen.svg)](https://gitter.im/rocketjob/support)
3
3
 
4
- Rocket Job is a distributed, priority-based, background job, computation system for Ruby.
5
- Rocket Job makes it easy to reliably process data using jobs written in Ruby.
6
-
7
- Outgrown existing Ruby background job processing solutions?
8
-
9
- Upgrade to Rocket Job.
10
- Or, start small with Rocket Job and seamlessly scale up to meet future business demands.
4
+ Ruby's missing batch system
11
5
 
12
6
  Checkout http://rocketjob.io/
13
7
 
@@ -23,6 +17,12 @@ Checkout http://rocketjob.io/
23
17
  * Questions? Join the chat room on Gitter for [rocketjob support](https://gitter.im/rocketjob/support)
24
18
  * [Report bugs](https://github.com/rocketjob/rocketjob/issues)
25
19
 
20
+ ## Ruby Support
21
+
22
+ Rocket Job is tested and supported on the following Ruby platforms:
23
+ - Ruby 2.1, 2.2, 2.3, and above
24
+ - JRuby 1.7.23, 9.0.5 and above
25
+
26
26
  ## Versioning
27
27
 
28
28
  This project uses [Semantic Versioning](http://semver.org/).
data/Rakefile CHANGED
@@ -1,6 +1,4 @@
1
- require 'rake/clean'
2
1
  require 'rake/testtask'
3
-
4
2
  require_relative 'lib/rocket_job/version'
5
3
 
6
4
  task :gem do
@@ -14,14 +12,10 @@ task publish: :gem do
14
12
  system "rm rocketjob-#{RocketJob::VERSION}.gem"
15
13
  end
16
14
 
17
- desc 'Run Test Suite'
18
- task :test do
19
- Rake::TestTask.new(:functional) do |t|
20
- t.test_files = FileList['test/**/*_test.rb']
21
- t.verbose = true
22
- end
23
-
24
- Rake::Task['functional'].invoke
15
+ Rake::TestTask.new(:test) do |t|
16
+ t.pattern = 'test/**/*_test.rb'
17
+ t.verbose = true
18
+ t.warning = false
25
19
  end
26
20
 
27
21
  task default: :test
@@ -1,5 +1,4 @@
1
1
  require 'optparse'
2
- require 'yaml'
3
2
  require 'semantic_logger'
4
3
  module RocketJob
5
4
  # Command Line Interface parser for RocketJob
@@ -25,7 +24,6 @@ module RocketJob
25
24
  setup_environment
26
25
  setup_logger
27
26
  rails? ? boot_rails : boot_standalone
28
- # setup_metrics
29
27
  write_pidfile
30
28
 
31
29
  opts = {}
@@ -34,15 +32,6 @@ module RocketJob
34
32
  Worker.run(opts)
35
33
  end
36
34
 
37
- def setup_metrics
38
- SemanticLogger.on_metric do |log|
39
- if log.metric.start_with?('rocketjob/')
40
- ap log
41
- RocketJob::Stats::ShortTerm.increment_metric(log.time, log.name, log.duration, log.metric_amount)
42
- end
43
- end
44
- end
45
-
46
35
  def rails?
47
36
  @rails ||= begin
48
37
  boot_file = Pathname.new(directory).join('config/environment.rb').expand_path
@@ -1,3 +1,4 @@
1
+ require 'yaml'
1
2
  # encoding: UTF-8
2
3
  module RocketJob
3
4
  # Centralized Configuration for Rocket Jobs
@@ -15,9 +16,9 @@ module RocketJob
15
16
  end
16
17
  end
17
18
 
18
- # Useful for Testing, not recommended elsewhere
19
- # By enabling inline_mode jobs will be called in-line using perform_now
20
- # No worker processes will be created, nor threads created
19
+ # Useful for Testing, not recommended elsewhere.
20
+ # When enabled all calls to `perform_later` will be redirected to `perform_now`.
21
+ # Also, exceptions will be raised instead of failing the job.
21
22
  cattr_accessor(:inline_mode) { false }
22
23
 
23
24
  # @formatter:off
@@ -222,7 +222,7 @@ module RocketJob
222
222
  }
223
223
  ]
224
224
  ).each do |result|
225
- counts[result['_id']] = result['count']
225
+ counts[result['_id'].to_sym] = result['count']
226
226
  end
227
227
  counts
228
228
  end
@@ -50,6 +50,7 @@ module AASM
50
50
  @states = orig.states.collect { |state| state.clone }
51
51
  @events = {}
52
52
  orig.events.each_pair { |name, event| @events[name] = event.clone }
53
+ @global_callbacks = @global_callbacks.dup
53
54
  end
54
55
  end
55
56
  end
@@ -0,0 +1,30 @@
1
+ # TODO Delete this file once PR has been accepted
2
+ # https://github.com/mongomapper/mongomapper/pull/641
3
+ MongoMapper::Plugins::Keys::Static
4
+ module MongoMapper
5
+ module Plugins
6
+ module Keys
7
+ module Static
8
+ module ClassMethods
9
+ def embedded_keys
10
+ @embedded_keys ||= embedded_associations.collect(&:as)
11
+ end
12
+
13
+ def embedded_key?(key)
14
+ embedded_keys.include?(key.to_sym)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def load_from_database(attrs, with_cast = false)
21
+ return super if !self.class.static_keys || !attrs.respond_to?(:each)
22
+
23
+ attrs = attrs.select { |key, _| self.class.key?(key) || self.class.embedded_key?(key) }
24
+
25
+ super(attrs, with_cast)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,51 @@
1
+ #require 'rocketjob'
2
+
3
+ module ActiveJob
4
+ module QueueAdapters
5
+ # == Rocket Job adapter for Active Job
6
+ #
7
+ # Ruby's missing batch system.
8
+ #
9
+ # Read more about Rocket Job {here}[http://rocketjob.io].
10
+ #
11
+ # To use Rocket Job set the queue_adapter config to +:rocket_job+.
12
+ #
13
+ # Rails.application.config.active_job.queue_adapter = :rocket_job
14
+ class RocketJobAdapter
15
+ def enqueue(active_job) #:nodoc:
16
+ rocket_job = JobWrapper.perform_later(active_job.serialize) do |job|
17
+ job.active_job_id = active_job.job_id
18
+ job.active_job_class = active_job.class.name
19
+ job.active_job_queue = active_job.queue_name
20
+ job.description = active_job.class.name
21
+ job.priority = active_job.priority if active_job.priority
22
+ end
23
+ active_job.provider_job_id = rocket_job.id.to_s
24
+ rocket_job
25
+ end
26
+
27
+ def enqueue_at(active_job, timestamp) #:nodoc:
28
+ rocket_job = JobWrapper.perform_later(active_job.serialize) do |job|
29
+ job.active_job_id = active_job.job_id
30
+ job.active_job_class = active_job.class.name
31
+ job.active_job_queue = active_job.queue_name
32
+ job.description = active_job.class.name
33
+ job.priority = active_job.priority if active_job.priority
34
+ job.run_at = Time.at(timestamp).utc
35
+ end
36
+ active_job.provider_job_id = rocket_job.id.to_s
37
+ rocket_job
38
+ end
39
+
40
+ class JobWrapper < RocketJob::Job #:nodoc:
41
+ key :active_job_id, String
42
+ key :active_job_class, String
43
+ key :active_job_queue, String
44
+
45
+ def perform(job_data)
46
+ Base.execute job_data
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,57 @@
1
+ module RocketJob
2
+ module Jobs
3
+ # Applies Retention policies to how long jobs are kept.
4
+ #
5
+ # Retentions are specific to each state so that for example completed
6
+ # jobs can be cleaned up before jobs that are running.
7
+ #
8
+ # Only one active instance of this housekeeping job is permitted at a time.
9
+ #
10
+ # Example:
11
+ # RocketJob::Jobs::HousekeepingJob.create!
12
+ #
13
+ # Example, with the default values that can be modified:
14
+ # RocketJob::Jobs::HousekeepingJob.create!(
15
+ # aborted_retention: 7.days,
16
+ # completed_retention: 7.days,
17
+ # failed_retention: 14.days,
18
+ # paused_retention: 90.days,
19
+ # queued_retention: nil
20
+ # )
21
+ #
22
+ # Example, overriding defaults and disabling removal of paused jobs:
23
+ # RocketJob::Jobs::HousekeepingJob.create!(
24
+ # aborted_retention: 1.day,
25
+ # completed_retention: 12.hours,
26
+ # failed_retention: 7.days,
27
+ # paused_retention: nil
28
+ # )
29
+ class HousekeepingJob < RocketJob::Job
30
+ include RocketJob::Plugins::Cron
31
+ include RocketJob::Plugins::Singleton
32
+
33
+ rocket_job do |job|
34
+ job.priority = 50
35
+ job.description = 'Cleans out historical jobs'
36
+ job.cron_schedule = '0 0 * * * America/New_York'
37
+ end
38
+
39
+ # Retention intervals in seconds
40
+ # Set to nil to not
41
+ key :aborted_retention, Integer, default: 7.days
42
+ key :completed_retention, Integer, default: 7.days
43
+ key :failed_retention, Integer, default: 14.days
44
+ key :paused_retention, Integer, default: 90.days
45
+ key :queued_retention, Integer
46
+
47
+ def perform
48
+ RocketJob::Job.where(state: :aborted, created_at: {'$lte' => aborted_retention.ago}).destroy_all if aborted_retention
49
+ RocketJob::Job.where(state: :completed, created_at: {'$lte' => completed_retention.ago}).destroy_all if completed_retention
50
+ RocketJob::Job.where(state: :failed, created_at: {'$lte' => failed_retention.ago}).destroy_all if failed_retention
51
+ RocketJob::Job.where(state: :paused, created_at: {'$lte' => paused_retention.ago}).destroy_all if paused_retention
52
+ RocketJob::Job.where(state: :queued, created_at: {'$lte' => queued_retention.ago}).destroy_all if queued_retention
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -107,6 +107,9 @@ module RocketJob
107
107
 
108
108
  key :cron_schedule, String
109
109
 
110
+ # Make cron_schedule editable for scheduled jobs
111
+ public_rocket_job_properties :cron_schedule
112
+
110
113
  before_create :rocket_job_set_run_at
111
114
 
112
115
  validates_presence_of :cron_schedule
@@ -8,20 +8,18 @@ module RocketJob
8
8
  module Plugins
9
9
  # Base class for storing models in MongoDB
10
10
  module Document
11
- autoload :Static, 'rocket_job/plugins/document/static'
12
-
13
11
  extend ActiveSupport::Concern
14
12
  include MongoMapper::Document
15
- include RocketJob::Plugins::Document::Static
16
13
 
17
14
  included do
18
- # Add after_initialize & after_find callbacks
19
- define_model_callbacks :initialize, :find, :only => [:after]
20
-
21
- # Prevent data in MongoDB from re-defining the model behavior
15
+ # Prevent data in MongoDB from re-defining the model behavior.
22
16
  self.static_keys = true
23
17
 
24
- # Turn off embedded callbacks. Slow and not used for Jobs
18
+ # Only save changes to this instance to prevent losing
19
+ # changes made by other processes or threads.
20
+ self.partial_updates = true
21
+
22
+ # Turn off embedded callbacks. Slow and not used by Jobs.
25
23
  embedded_callbacks_off
26
24
  end
27
25
 
@@ -38,21 +36,6 @@ module RocketJob
38
36
  end
39
37
  end
40
38
 
41
- # Add after_initialize callbacks
42
- # TODO: Remove after new MongoMapper gem is released
43
- # Also remove define_model_callbacks above
44
- def initialize(*)
45
- run_callbacks(:initialize) { super }
46
- end
47
-
48
- def initialize_from_database(*)
49
- run_callbacks(:initialize) do
50
- run_callbacks(:find) do
51
- super
52
- end
53
- end
54
- end
55
-
56
39
  private
57
40
 
58
41
  def update_attributes_and_reload(attrs)
@@ -109,7 +109,7 @@ module RocketJob
109
109
  }
110
110
  ]
111
111
  ).each do |result|
112
- counts[result['_id']] = result['count']
112
+ counts[result['_id'].to_sym] = result['count']
113
113
  end
114
114
 
115
115
  # Calculate :queued_now and :scheduled if there are queued jobs
@@ -69,7 +69,10 @@ module RocketJob
69
69
 
70
70
  # Requeues all jobs that were running on worker that died
71
71
  def self.requeue_dead_worker(worker_name)
72
- running.each { |job| job.requeue!(worker_name) if job.may_requeue?(worker_name) }
72
+ # TODO Need to requeue paused, failed since user may have transitioned job before it finished
73
+ running.each do |job|
74
+ job.requeue!(worker_name) if job.may_requeue?(worker_name)
75
+ end
73
76
  end
74
77
 
75
78
  # Turn off embedded callbacks. Slow and not used for Jobs
@@ -97,7 +100,7 @@ module RocketJob
97
100
  worker = RocketJob::Worker.new(name: 'inline')
98
101
  worker.started
99
102
  start if may_start?
100
- # Raise exceptions
103
+ # Re-Raise exceptions
101
104
  rocket_job_work(worker, true) if running?
102
105
  result
103
106
  end
@@ -113,10 +116,10 @@ module RocketJob
113
116
  # worker_name: [String]
114
117
  # Name of the worker on which the exception has occurred
115
118
  #
116
- # raise_exceptions: [true|false]
119
+ # re_raise_exceptions: [true|false]
117
120
  # Re-raise the exception after updating the job
118
- # Default: !RocketJob::Config.inline_mode
119
- def rocket_job_fail_on_exception!(worker_name, raise_exceptions = !RocketJob::Config.inline_mode)
121
+ # Default: false
122
+ def rocket_job_fail_on_exception!(worker_name, re_raise_exceptions = false)
120
123
  yield
121
124
  rescue Exception => exc
122
125
  if failed? || !may_fail?
@@ -130,7 +133,7 @@ module RocketJob
130
133
  fail!(worker_name, exc)
131
134
  end
132
135
  end
133
- raise exc if raise_exceptions
136
+ raise exc if re_raise_exceptions
134
137
  end
135
138
 
136
139
  # Works on this job
@@ -141,9 +144,9 @@ module RocketJob
141
144
  # is set in the job itself.
142
145
  #
143
146
  # Thread-safe, can be called by multiple threads at the same time
144
- def rocket_job_work(worker, raise_exceptions = !RocketJob::Config.inline_mode)
147
+ def rocket_job_work(worker, re_raise_exceptions = false)
145
148
  raise(ArgumentError, 'Job must be started before calling #rocket_job_work') unless running?
146
- rocket_job_fail_on_exception!(worker.name, raise_exceptions) do
149
+ rocket_job_fail_on_exception!(worker.name, re_raise_exceptions) do
147
150
  run_callbacks :perform do
148
151
  # Allow callbacks to fail, complete or abort the job
149
152
  if running?
@@ -18,7 +18,7 @@ module RocketJob
18
18
  extend ActiveSupport::Concern
19
19
 
20
20
  # Attributes to exclude when copying across the attributes to the new instance
21
- RESTART_EXCLUDES = %w(_id state created_at started_at completed_at failure_count worker_name percent_complete exception result run_at)
21
+ 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)
22
22
 
23
23
  included do
24
24
  after_abort :rocket_job_restart_new_instance
@@ -0,0 +1,101 @@
1
+ # encoding: UTF-8
2
+ require 'active_support/concern'
3
+
4
+ module RocketJob
5
+ module Plugins
6
+ # Automatically retry the job on failure.
7
+ #
8
+ # The following retry algorithm is used to automatically retry a job when it fails:
9
+ # Failed jobs are aborted so that they cannot be restarted since a new instance has there are workers
10
+ # available to run. For example if workers are busy working on higher priority jobs, then the job
11
+ # will only run once those jobs have completed, or their priority lowered. Additionally, while the
12
+ # job is queued no additional instances will be enqueued, even if the next cron interval has been reached.
13
+ #
14
+ # Note:
15
+ # - After failure the job is scheduled to run again in the future.
16
+ # - The job will not be retried if:
17
+ # - The job has expired.
18
+ # - The job fails validations.
19
+ # - The number of retry counts has been exceeded.
20
+ # - To see the number of times a job has failed so far:
21
+ # job.failure_count
22
+ #
23
+ # Example:
24
+ #
25
+ # class MyJob < RocketJob::Job
26
+ # include RocketJob::Plugins::Retry
27
+ #
28
+ # # Set the default retry_count
29
+ # rocket_job do |job|
30
+ # job.max_retries = 3
31
+ # end
32
+ #
33
+ # def perform
34
+ # puts "DONE"
35
+ # end
36
+ # end
37
+ #
38
+ # # Queue the job for processing using the default cron_schedule specified above
39
+ # MyJob.create!
40
+ #
41
+ # # Replace the default retry_count
42
+ # MyCronJob.create!(max_retries: 10)
43
+ #
44
+ # # Disable retries for this job instance
45
+ # MyCronJob.create!(max_retries: 0)
46
+ #
47
+ module Retry
48
+ extend ActiveSupport::Concern
49
+
50
+ included do
51
+ after_fail :rocket_job_retry
52
+
53
+ # Maximum number of times to retry this job
54
+ # 25 is approximately 3 weeks of retries
55
+ key :max_retries, Integer, default: 25
56
+
57
+ # List of times when this job failed
58
+ key :failed_times, Array
59
+
60
+ # Make max_retries editable in Rocket Job Mission Control
61
+ public_rocket_job_properties :max_retries
62
+
63
+ validates_presence_of :max_retries
64
+ end
65
+
66
+ # Returns [true|false] whether this job will be automatically retried on failure
67
+ def rocket_job_retry_on_fail?
68
+ failure_count > max_retries
69
+ end
70
+
71
+ private
72
+
73
+ def rocket_job_retry
74
+ # Failure count is incremented during before_fail
75
+ return if expired? || !rocket_job_retry_on_fail?
76
+
77
+ delay_seconds = rocket_job_retry_seconds_to_delay
78
+ logger.info "Job failed, automatically retrying in #{delay_seconds} seconds. Retry count: #{failure_count}"
79
+
80
+ now = Time.now
81
+ self.run_at = now + delay_seconds
82
+ self.failed_times << now
83
+ new_record? ? retry : retry!
84
+ end
85
+
86
+ # Prevent exception from being cleared on retry
87
+ def rocket_job_clear_exception
88
+ self.completed_at = nil
89
+ self.exception = nil unless rocket_job_retry_on_fail?
90
+ self.worker_name = nil
91
+ end
92
+
93
+ # Returns [Time] when to retry this job at
94
+ # Same basic formula as Sidekiq and Delayed Job
95
+ def rocket_job_retry_seconds_to_delay
96
+ (failure_count ** 4) + 15 + (rand(30)*(failure_count+1))
97
+ end
98
+
99
+ end
100
+ end
101
+ end
@@ -1,4 +1,4 @@
1
1
  # encoding: UTF-8
2
2
  module RocketJob #:nodoc
3
- VERSION = '2.0.0'
3
+ VERSION = '2.1.1'
4
4
  end
@@ -178,7 +178,7 @@ module RocketJob
178
178
  }
179
179
  ]
180
180
  ).each do |result|
181
- counts[result['_id']] = result['count']
181
+ counts[result['_id'].to_sym] = result['count']
182
182
  end
183
183
  counts
184
184
  end
@@ -195,7 +195,7 @@ module RocketJob
195
195
  # - The worker process is "hanging"
196
196
  # - The worker is no longer able to communicate with the MongoDB Server
197
197
  def zombie?(missed = 4)
198
- return false unless running?
198
+ return false unless running? || stopping?
199
199
  return true if heartbeat.nil? || heartbeat.updated_at.nil?
200
200
  dead_seconds = Config.instance.heartbeat_seconds * missed
201
201
  (Time.now - heartbeat.updated_at) >= dead_seconds
@@ -260,13 +260,25 @@ module RocketJob
260
260
  # Stop worker if shutdown indicator was set
261
261
  stop! if self.class.shutdown? && may_stop?
262
262
  end
263
+
263
264
  logger.info 'Waiting for worker threads to stop'
264
- # TODO Put a timeout on join.
265
- # Log Thread dump for active threads
266
- # Compare thread dumps for any changes, force down if no change?
267
- # reload, if model missing: Send Shutdown exception to each thread
268
- # 5 more seconds then exit
269
- worker_threads.each { |t| t.join }
265
+ while thread = worker_threads.first
266
+ if thread.join(5)
267
+ # Worker thread is dead
268
+ worker_threads.shift
269
+ else
270
+ # Timeout waiting for thread to stop
271
+ begin
272
+ update_attributes_and_reload(
273
+ 'heartbeat.updated_at' => Time.now,
274
+ 'heartbeat.current_threads' => worker_count
275
+ )
276
+ rescue MongoMapper::DocumentNotFound
277
+ logger.error('Worker has been destroyed. Going down hard!')
278
+ break
279
+ end
280
+ end
281
+ end
270
282
  logger.info 'Shutdown'
271
283
  rescue Exception => exc
272
284
  logger.error('RocketJob::Worker is stopping due to an exception', exc)
@@ -336,6 +348,8 @@ module RocketJob
336
348
  logger.info "Stopping. Worker state: #{state.inspect}"
337
349
  rescue Exception => exc
338
350
  logger.fatal('Unhandled exception in job processing thread', exc)
351
+ ensure
352
+ ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
339
353
  end
340
354
 
341
355
  # Process the next available job
data/lib/rocketjob.rb CHANGED
@@ -3,6 +3,7 @@ require 'semantic_logger'
3
3
  require 'rocket_job/extensions/mongo'
4
4
  require 'mongo_ha'
5
5
  require 'mongo_mapper'
6
+ require 'rocket_job/extensions/mongo_mapper'
6
7
  require 'rocket_job/version'
7
8
 
8
9
  # @formatter:off
@@ -65,3 +66,6 @@ module RocketJob
65
66
  end
66
67
 
67
68
  end
69
+
70
+ # Add Active Job adapter for Rails
71
+ require 'rocket_job/extensions/rocket_job_adapter' if defined?(ActiveJob)
@@ -207,7 +207,7 @@ class DirmonEntryTest < Minitest::Test
207
207
  @file_name = @file.path
208
208
  @pathname = Pathname.new(@file_name)
209
209
  File.open(@file_name, 'w') { |file| file.write('Hello World') }
210
- assert File.exists?(@file_name)
210
+ assert File.exist?(@file_name)
211
211
  @archive_real_name = @archive_path.join("#{@job.id}_#{File.basename(@file_name)}").to_s
212
212
  end
213
213
 
@@ -230,7 +230,7 @@ class DirmonEntryTest < Minitest::Test
230
230
  describe '#archive_file' do
231
231
  it 'archive file' do
232
232
  assert_equal @archive_real_name, @entry.send(:archive_file, @job, Pathname.new(@file_name))
233
- assert File.exists?(@archive_real_name)
233
+ assert File.exist?(@archive_real_name)
234
234
  end
235
235
  end
236
236
 
@@ -17,6 +17,7 @@ module Plugins
17
17
 
18
18
  describe RocketJob::Plugins::Job::Persistence do
19
19
  before do
20
+ RocketJob::Job.destroy_all
20
21
  @description = 'Hello World'
21
22
  @arguments = [{key: 'value'}]
22
23
  @job = PersistJob.new(
@@ -28,6 +29,8 @@ module Plugins
28
29
 
29
30
  after do
30
31
  @job.destroy if @job && !@job.new_record?
32
+ @job2.destroy if @job2 && !@job2.new_record?
33
+ @job3.destroy if @job3 && !@job3.new_record?
31
34
  end
32
35
 
33
36
  describe '.config' do
@@ -75,6 +78,20 @@ module Plugins
75
78
  end
76
79
  end
77
80
 
81
+ describe '.counts_by_state' do
82
+ it 'returns states as symbols' do
83
+ @job.start!
84
+ @job2 = PersistJob.create!(arguments: [{key: 'value'}])
85
+ @job3 = PersistJob.create!(arguments: [{key: 'value'}], run_at: 1.day.from_now)
86
+ counts = RocketJob::Job.counts_by_state
87
+ assert_equal 4, counts.size, counts.ai
88
+ assert_equal 1, counts[:running]
89
+ assert_equal 2, counts[:queued]
90
+ assert_equal 1, counts[:queued_now]
91
+ assert_equal 1, counts[:scheduled]
92
+ end
93
+ end
94
+
78
95
  end
79
96
  end
80
97
  end
@@ -78,7 +78,7 @@ module Plugins
78
78
  @job = ProcessingWindowJob.new
79
79
  refute @job.valid?
80
80
  assert_equal "can't be blank", @job.errors.messages[:processing_schedule].first
81
- assert_equal "not a string: nil", @job.errors.messages[:processing_schedule].second
81
+ assert_equal 'not a string: nil', @job.errors.messages[:processing_schedule].second
82
82
  assert_equal "can't be blank", @job.errors.messages[:processing_duration].first
83
83
  end
84
84
 
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: 2.0.0
4
+ version: 2.1.1
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-02-27 00:00:00.000000000 Z
11
+ date: 2016-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: mongo_mapper
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '0.13'
47
+ version: 0.14.0.rc1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '0.13'
54
+ version: 0.14.0.rc1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: semantic_logger
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,38 +66,23 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.1'
69
- - !ruby/object:Gem::Dependency
70
- name: symmetric-encryption
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '3.0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '3.0'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: aasm
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
- - - ">="
73
+ - - "~>"
88
74
  - !ruby/object:Gem::Version
89
75
  version: '4.3'
90
76
  type: :runtime
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
- - - ">="
80
+ - - "~>"
95
81
  - !ruby/object:Gem::Version
96
82
  version: '4.3'
97
- description: Batch Processing System focused on performance, scalability, reliability,
98
- and visibility of every job in the system.
83
+ description:
99
84
  email:
100
- - reidmo@gmail.com
85
+ - support@rocketjob.io
101
86
  executables:
102
87
  - rocketjob
103
88
  - rocketjob_perf
@@ -114,15 +99,17 @@ files:
114
99
  - lib/rocket_job/dirmon_entry.rb
115
100
  - lib/rocket_job/extensions/aasm.rb
116
101
  - lib/rocket_job/extensions/mongo.rb
102
+ - lib/rocket_job/extensions/mongo_mapper.rb
103
+ - lib/rocket_job/extensions/rocket_job_adapter.rb
117
104
  - lib/rocket_job/heartbeat.rb
118
105
  - lib/rocket_job/job.rb
119
106
  - lib/rocket_job/job_exception.rb
120
107
  - lib/rocket_job/jobs/dirmon_job.rb
108
+ - lib/rocket_job/jobs/housekeeping_job.rb
121
109
  - lib/rocket_job/jobs/simple_job.rb
122
110
  - lib/rocket_job/performance.rb
123
111
  - lib/rocket_job/plugins/cron.rb
124
112
  - lib/rocket_job/plugins/document.rb
125
- - lib/rocket_job/plugins/document/static.rb
126
113
  - lib/rocket_job/plugins/job/callbacks.rb
127
114
  - lib/rocket_job/plugins/job/defaults.rb
128
115
  - lib/rocket_job/plugins/job/logger.rb
@@ -132,6 +119,7 @@ files:
132
119
  - lib/rocket_job/plugins/job/worker.rb
133
120
  - lib/rocket_job/plugins/processing_window.rb
134
121
  - lib/rocket_job/plugins/restart.rb
122
+ - lib/rocket_job/plugins/retry.rb
135
123
  - lib/rocket_job/plugins/rufus/cron_line.rb
136
124
  - lib/rocket_job/plugins/rufus/zo_time.rb
137
125
  - lib/rocket_job/plugins/singleton.rb
@@ -179,10 +167,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
179
167
  version: '0'
180
168
  requirements: []
181
169
  rubyforge_project:
182
- rubygems_version: 2.4.8
170
+ rubygems_version: 2.5.1
183
171
  signing_key:
184
172
  specification_version: 4
185
- summary: Batch Processing System for Ruby
173
+ summary: Ruby's missing batch system.
186
174
  test_files:
187
175
  - test/config/mongo.yml
188
176
  - test/config_test.rb
@@ -1,53 +0,0 @@
1
- module RocketJob
2
- module Plugins
3
- # Extension for Document to implement static keys
4
- # Remove when new MongoMapper gem is released
5
- module Document
6
- module Static
7
- extend ActiveSupport::Concern
8
-
9
- module ClassMethods
10
- attr_writer :static_keys
11
-
12
- def static_keys
13
- @static_keys || false
14
- end
15
-
16
- def embedded_keys
17
- @embedded_keys ||= embedded_associations.collect(&:as)
18
- end
19
-
20
- def embedded_key?(key)
21
- embedded_keys.include?(key.to_sym)
22
- end
23
- end
24
-
25
- def read_key(name)
26
- if !self.class.static_keys || self.class.key?(name)
27
- super
28
- else
29
- raise MissingKeyError, "Tried to read the key #{name.inspect}, but no key was defined. Either define key :#{name} or set self.static_keys = false"
30
- end
31
- end
32
-
33
- private
34
-
35
- def write_key(name, value)
36
- if !self.class.static_keys || self.class.key?(name)
37
- super
38
- else
39
- raise MissingKeyError, "Tried to write the key #{name.inspect}, but no key was defined. Either define key :#{name} or set self.static_keys = false"
40
- end
41
- end
42
-
43
- def load_from_database(attrs, with_cast = false)
44
- return super if !self.class.static_keys || !attrs.respond_to?(:each)
45
-
46
- attrs = attrs.select { |key, _| self.class.key?(key) || self.class.embedded_key?(key) }
47
-
48
- super(attrs, with_cast)
49
- end
50
- end
51
- end
52
- end
53
- end