rocketjob 2.0.0 → 2.1.1

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