scheduled_job 0.0.9 → 0.1.0

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: 4e237cb5535336997a5bc97f2ccc0092f038ce5c
4
- data.tar.gz: dd0f0331da06bf19651c16b3216fa2f29fb778a5
3
+ metadata.gz: 8992a23a08c1f37078a3f9a41e3e79807ccdcd86
4
+ data.tar.gz: f0fa25cd3bd9e27fb4b827a76e0c581f558ea451
5
5
  SHA512:
6
- metadata.gz: c581219617e217ca776697a98fac4b82b6369a1cb317b90c9f2509c148d1ce599173d7f7443f4b0af65324bfe0fb2ae39ddebeae3157c9c9264c9c22ff884cd1
7
- data.tar.gz: 8f7718d33ca84cad2ae07a12705b8781a14d01230b1e3f5ac96b7806ca2a477b140ec480e0ec7d99e939d4312ec4619450dd7503f336799c1f74d361d18bac8c
6
+ metadata.gz: 3bdada7d253e3124f3ef9ac9e303015a80082a8e3ef3ba61a2f34a30c9b6de9ee3e9ad238484e2d280b4b1bad61efc07144611f56f942b18d80c53d481a98b4e
7
+ data.tar.gz: b7da6a1ed79dab91050c9bec04668117b37ec2688f7726aeca25b99b8f5f76590ec2269b454bc68b218b0d24e02a831876aaca816804dd62b75d1aff379e2ea4
data/CHANGELOG.md CHANGED
@@ -1,2 +1,24 @@
1
1
  # 0.0.2
2
2
  Initial public release
3
+
4
+ # 0.0.3
5
+ Removing hard coded Delayed Job dependencies
6
+
7
+ # 0.0.4
8
+ Adds one second back off to the fast mode
9
+
10
+ # 0.0.5
11
+ Removed the compulsory .configure call
12
+
13
+ # 0.0.7
14
+ Fixes substring job lookup bug
15
+
16
+ # 0.0.8
17
+ Bug fix for multiple scheduling potential
18
+
19
+ # 0.0.9
20
+ Adds local db for development
21
+
22
+ # 0.1.0
23
+ Makes available the `rake jobs:reschedule` rake task
24
+ Adds a config to allow the scheduling for more than one instance of the same job
data/README.md CHANGED
@@ -92,7 +92,7 @@ First you must include the scheduled job module in any DelayedJob that needs to
92
92
  include ::ScheduledJob
93
93
  ```
94
94
 
95
- Then you need to say what the job is acutally to do. This is done by implementing the permform method.
95
+ Then you need to say what the job is actually to do. This is done by implementing the perform method.
96
96
 
97
97
  ```ruby
98
98
  def perform
@@ -100,7 +100,7 @@ def perform
100
100
  end
101
101
  ```
102
102
 
103
- Finaly we need to write the logic for when we want the job to run. This is done by implementing the time_to_recur method which is passed the time the job last completed as its parameter.
103
+ Finally we need to write the logic for when we want the job to run. This is done by implementing the time_to_recur method which is passed the time the job last completed as its parameter.
104
104
 
105
105
  ```ruby
106
106
  def self.time_to_recur(last_run_at)
@@ -108,6 +108,18 @@ def self.time_to_recur(last_run_at)
108
108
  end
109
109
  ```
110
110
 
111
+ Recently added is the new jobs configuration. This adds two major new benefits. Firstly this will allow you to define jobs that are allow to run in multiple instances. Say for example that there should always be two instances of a given job running. This can now be defined using the following configuration:
112
+
113
+ ```ruby
114
+ ScheduledJob.configure do |config|
115
+ config.jobs = {
116
+ MyAwesomeParallelJobClass => { count: 2 }
117
+ }
118
+ end
119
+ ```
120
+
121
+ This lets scheduled job know that it is OK to have two pending job instances for MyAwesomeParallelJobClass in the delayed job table. Additionally by using this configuration you also get access to the new reschedule rake task for free. ScheduledJob now adds `rake jobs:reschedule`. This will loop through your jobs configuration and automatically call schedule job up to the number of times you intend the jobs pending. This is useful for heavy users of scheduled job to "prime" your database with your recurring jobs. Note you can still add jobs to this configuration that you do not want any instances of by setting the count to 0. This is useful if you are looking to access all classes you have that you have registered with scheduled job.
122
+
111
123
  There are also callbacks that are available using ScheduledJob. These allow you to hook into the scheduling life cycle. Also note that as this uses DelayedJob under the hood all of the delayed job callbacks are still available for use.
112
124
 
113
125
  These can be defined when configuring the gem for you application on the configure block:
@@ -126,7 +138,7 @@ config.before_callback = -> (job, scheduled_job) do
126
138
  end
127
139
  ```
128
140
 
129
- The success_callback is called on sucessful completion of the job and is also passed the delayed job object and the scheduled job instance.
141
+ The success_callback is called on successful completion of the job and is also passed the delayed job object and the scheduled job instance.
130
142
 
131
143
  ```ruby
132
144
  config.success_callback = -> (job, _) do
@@ -134,7 +146,7 @@ config.success_callback = -> (job, _) do
134
146
  end
135
147
  ```
136
148
 
137
- Then there is the fast mode. This is checked prior to scheduling another run of your job e.g. after a job has completed. This allows you to override the scheduling logic and ask the job to run immediatly. This is passed the scheduled job class. This means you can have state stored elsewhere to change the scheduling without having to modify the code. This could be getting an array from a database for example:
149
+ Then there is the fast mode. This is checked prior to scheduling another run of your job e.g. after a job has completed. This allows you to override the scheduling logic and ask the job to run immediately. This is passed the scheduled job class. This means you can have state stored elsewhere to change the scheduling without having to modify the code. This could be getting an array from a database for example:
138
150
 
139
151
  ```ruby
140
152
  config.fast_mode = -> (job) do
data/lib/scheduled_job.rb CHANGED
@@ -5,6 +5,9 @@ require 'delayed_job_active_record'
5
5
  require File.dirname(__FILE__) + '/tasks/jobs.rb'
6
6
 
7
7
  module ScheduledJob
8
+ class ConfigError < StandardError
9
+ end
10
+
8
11
  class << self
9
12
  attr_writer :config
10
13
  def config
@@ -12,32 +15,43 @@ module ScheduledJob
12
15
  end
13
16
  end
14
17
 
18
+ def self.reschedule
19
+ config.jobs.each do |job, options|
20
+ options[:count].times do
21
+ job.schedule_job
22
+ end
23
+ end if config.jobs
24
+ end
25
+
15
26
  def self.logger
16
27
  self.config.logger
17
28
  end
18
29
 
19
30
  def self.configure
20
31
  yield(config)
32
+ validate_job_hash(config.jobs) if config.jobs
33
+ end
34
+
35
+ def self.validate_job_hash(jobs)
36
+ jobs.each do |klass, options|
37
+ raise ConfigError.new("Jobs config found invalid class: #{klass}") unless klass.class == Class
38
+ raise ConfigError.new("Jobs config found invalid job count: #{options[:count]}") unless options[:count].to_i >= 0
39
+ end
21
40
  end
22
41
 
23
42
  class Config
24
- attr_accessor :logger, :before_callback, :success_callback, :fast_mode
43
+ attr_accessor :logger, :before_callback, :success_callback, :fast_mode, :jobs
25
44
 
26
45
  def initialize
46
+ @jobs ||= {}
27
47
  @logger = Logger.new(STDOUT)
28
48
  end
29
49
  end
30
50
 
31
51
  def self.included(base)
32
- @classes ||= []
33
- @classes << base.name.constantize
34
52
  base.extend ScheduledJobClassMethods
35
53
  end
36
54
 
37
- def self.classes
38
- @classes
39
- end
40
-
41
55
  def before(job)
42
56
  callback = ScheduledJob.config.before_callback
43
57
  callback.call(job, self) if callback
@@ -65,7 +79,7 @@ module ScheduledJob
65
79
  # This method should be called when scheduling a recurring job as it checks to ensure no
66
80
  # other instances of the job are already running.
67
81
  def schedule_job(job = nil)
68
- unless job_exists?(job)
82
+ if can_schedule_job?(job)
69
83
  callback = ScheduledJob.config.fast_mode
70
84
  in_fast_mode = callback ? callback.call(self) : false
71
85
 
@@ -84,13 +98,20 @@ module ScheduledJob
84
98
  (base + Random.new.rand((-1 * random_delta)..random_delta)).minutes
85
99
  end
86
100
 
87
- def job_exists?(job = nil)
101
+ def can_schedule_job?(job = nil)
88
102
  conditions = ['(handler like ? OR handler like ?) AND failed_at IS NULL', "%:#{self.name} %", "%:#{self.name}\n%"]
89
103
  unless job.blank?
90
104
  conditions[0] << " AND id != ?"
91
105
  conditions << job.id
92
106
  end
93
- Delayed::Job.exists?(conditions)
107
+ job_count = Delayed::Job.where(conditions).count
108
+ intended_job_count = 1
109
+
110
+ if ScheduledJob.config.jobs && ScheduledJob.config.jobs[self.name]
111
+ intended_job_count = ScheduledJob.config.jobs[self.name][:count]
112
+ end
113
+
114
+ job_count < intended_job_count
94
115
  end
95
116
 
96
117
  def run_duration_threshold
@@ -1,3 +1,3 @@
1
1
  module ScheduledJob
2
- VERSION = "0.0.9"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/tasks/jobs.rb CHANGED
@@ -5,20 +5,10 @@ module ScheduledJob
5
5
  include Rake::DSL if defined? Rake::DSL
6
6
 
7
7
  def install_tasks
8
- def check_schedule_job(job)
9
- if job.respond_to?(:time_to_recur)
10
- job.schedule_job
11
- else
12
- job.descendants.each { |j| check_schedule_job(j) }
13
- end
14
- end
15
-
16
8
  namespace:jobs do
17
9
  desc "Will schedule all scheduled jobs"
18
10
  task :reschedule => :environment do
19
- ScheduledJob.classes.each do |job|
20
- check_schedule_job(job)
21
- end
11
+ ScheduledJob.reschedule
22
12
  end
23
13
  end
24
14
  end
@@ -20,6 +20,7 @@ class Test < UnderTest
20
20
  end
21
21
 
22
22
  describe ScheduledJob do
23
+ before { ScheduledJob.configure { |config| config.jobs = nil } }
23
24
 
24
25
  let(:under_test) { UnderTest.new }
25
26
 
@@ -37,8 +38,59 @@ describe ScheduledJob do
37
38
  end
38
39
  end
39
40
 
41
+ describe 'job config' do
42
+ it 'takes a jobs hash config' do
43
+ expect {
44
+ ScheduledJob.configure do |config|
45
+ config.jobs = {
46
+ UnderTest => { count: 1 }
47
+ }
48
+ end
49
+ }.not_to raise_error
50
+ end
51
+
52
+ context 'validates the job hash' do
53
+ it 'detects an bad job class' do
54
+ expect {
55
+ ScheduledJob.configure do |config|
56
+ config.jobs = {
57
+ 'UnderTest' => { count: 1 }
58
+ }
59
+ end
60
+ }.to raise_error(ScheduledJob::ConfigError)
61
+ end
62
+
63
+ it 'detects a bad job count' do
64
+ expect {
65
+ ScheduledJob.configure do |config|
66
+ config.jobs = {
67
+ UnderTest => { count: -1 }
68
+ }
69
+ end
70
+ }.to raise_error(ScheduledJob::ConfigError)
71
+ end
72
+ end
73
+ end
74
+
75
+ describe 'reschedule' do
76
+ before do
77
+ ScheduledJob.configure do |config|
78
+ config.jobs = {
79
+ UnderTest => { count: 1 },
80
+ Test => { count: 5 }
81
+ }
82
+ end
83
+ end
84
+
85
+ it 'calls reschedule on all config jobs up to the job count limit' do
86
+ expect(UnderTest).to receive(:schedule_job).once
87
+ expect(Test).to receive(:schedule_job).exactly(5).times
88
+ ScheduledJob.reschedule
89
+ end
90
+ end
91
+
40
92
  describe 'fast mode' do
41
- before { expect(Delayed::Job).to receive(:exists?).and_return(false) }
93
+ before { expect(Delayed::Job).to receive(:where).and_return([]) }
42
94
 
43
95
  context 'when the job is not in run fast mode' do
44
96
  it 'uses the value from time to recur' do
@@ -121,7 +173,7 @@ describe ScheduledJob do
121
173
  allow(job).to receive(:id) { 4 }
122
174
  instance = double("instance")
123
175
  allow(UnderTest).to receive(:new) { instance }
124
- expect(Delayed::Job).to receive(:exists?).and_return(false)
176
+ expect(Delayed::Job).to receive(:where).and_return([])
125
177
  expect(Delayed::Job).to receive(:enqueue).with(instance, run_at: "time to recur", queue: "TESTING")
126
178
  UnderTest.schedule_job job
127
179
  end
@@ -136,7 +188,7 @@ describe ScheduledJob do
136
188
  dummy_job = double("job")
137
189
  allow(dummy_job).to receive(:id)
138
190
  expect(dummy_job).to receive(:update_attributes!)
139
- expect(Delayed::Job).to receive(:exists?).twice.and_return(false)
191
+ expect(Delayed::Job).to receive(:where).twice.and_return([])
140
192
  expect(Delayed::Job).to receive(:enqueue).exactly(2).times
141
193
  UnderTest.schedule_job
142
194
  under_test.failure(dummy_job)
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'pry'
1
2
  require 'simplecov'
2
3
  SimpleCov.start
3
4
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scheduled_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - CallumD
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2015-02-02 00:00:00.000000000 Z
14
+ date: 2015-02-16 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: delayed_job