delayed_cron 0.2.0
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 +7 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +26 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +153 -0
- data/README.md +66 -0
- data/Rakefile +11 -0
- data/delayed_cron.gemspec +26 -0
- data/init.rb +4 -0
- data/lib/delayed_cron.rb +77 -0
- data/lib/delayed_cron/jobs.rb +7 -0
- data/lib/delayed_cron/jobs/delayed_job.rb +32 -0
- data/lib/delayed_cron/jobs/resque.rb +23 -0
- data/lib/delayed_cron/jobs/sidekiq.rb +31 -0
- data/lib/delayed_cron/railtie.rb +27 -0
- data/lib/delayed_cron/version.rb +3 -0
- data/rails/init.rb +2 -0
- data/spec/delayed_cron_spec.rb +107 -0
- data/spec/spec_helper.rb +49 -0
- metadata +190 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 94f054b61256b70c12f19fbfc15024292871e8bf
|
|
4
|
+
data.tar.gz: 49375bc979792142eb6aa97101cfbde263ebfbe8
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 61556046658861b399467d0a9e900b5dff1d5f28ac8b8b9a33dc67aedb0fb7480ece60b844cc4856ddebf257969a4a674fc3d22031dbc7aa5eeba96855fb4e19
|
|
7
|
+
data.tar.gz: 688d84742e71d507e024616d08fba3c911d5289d89b11f339bd595dafc12c0be6bc3470db4bee991cb01f7a2f552d1083b02acd1b0305216898642b0b150a96c
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ruby-2.0.0-p247
|
data/.travis.yml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
language: ruby
|
|
2
|
+
rvm:
|
|
3
|
+
- 2.0.0
|
|
4
|
+
|
|
5
|
+
matrix:
|
|
6
|
+
allow_failures:
|
|
7
|
+
- rvm: rbx-19mode
|
|
8
|
+
|
|
9
|
+
services:
|
|
10
|
+
- redis
|
|
11
|
+
|
|
12
|
+
script:
|
|
13
|
+
- bundle exec rake
|
|
14
|
+
|
|
15
|
+
addons:
|
|
16
|
+
code_climate:
|
|
17
|
+
repo_token: f0884115cadbe82b33756e38a9cd32d5129304746a17126d6c7da02e7a69910a
|
|
18
|
+
|
|
19
|
+
notifications:
|
|
20
|
+
email:
|
|
21
|
+
- justin@jgrubbs.net
|
|
22
|
+
|
|
23
|
+
gemfile:
|
|
24
|
+
- Gemfile
|
|
25
|
+
|
|
26
|
+
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
delayed_cron (0.1.0)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
actionmailer (4.0.4)
|
|
10
|
+
actionpack (= 4.0.4)
|
|
11
|
+
mail (~> 2.5.4)
|
|
12
|
+
actionpack (4.0.4)
|
|
13
|
+
activesupport (= 4.0.4)
|
|
14
|
+
builder (~> 3.1.0)
|
|
15
|
+
erubis (~> 2.7.0)
|
|
16
|
+
rack (~> 1.5.2)
|
|
17
|
+
rack-test (~> 0.6.2)
|
|
18
|
+
activemodel (4.0.4)
|
|
19
|
+
activesupport (= 4.0.4)
|
|
20
|
+
builder (~> 3.1.0)
|
|
21
|
+
activerecord (4.0.4)
|
|
22
|
+
activemodel (= 4.0.4)
|
|
23
|
+
activerecord-deprecated_finders (~> 1.0.2)
|
|
24
|
+
activesupport (= 4.0.4)
|
|
25
|
+
arel (~> 4.0.0)
|
|
26
|
+
activerecord-deprecated_finders (1.0.3)
|
|
27
|
+
activesupport (4.0.4)
|
|
28
|
+
i18n (~> 0.6, >= 0.6.9)
|
|
29
|
+
minitest (~> 4.2)
|
|
30
|
+
multi_json (~> 1.3)
|
|
31
|
+
thread_safe (~> 0.1)
|
|
32
|
+
tzinfo (~> 0.3.37)
|
|
33
|
+
arel (4.0.2)
|
|
34
|
+
atomic (1.1.15)
|
|
35
|
+
builder (3.1.4)
|
|
36
|
+
celluloid (0.15.2)
|
|
37
|
+
timers (~> 1.1.0)
|
|
38
|
+
codeclimate-test-reporter (0.3.0)
|
|
39
|
+
simplecov (>= 0.7.1, < 1.0.0)
|
|
40
|
+
columnize (0.3.6)
|
|
41
|
+
connection_pool (1.2.0)
|
|
42
|
+
debugger (1.6.6)
|
|
43
|
+
columnize (>= 0.3.1)
|
|
44
|
+
debugger-linecache (~> 1.2.0)
|
|
45
|
+
debugger-ruby_core_source (~> 1.3.2)
|
|
46
|
+
debugger-linecache (1.2.0)
|
|
47
|
+
debugger-ruby_core_source (1.3.2)
|
|
48
|
+
delayed_job (4.0.0)
|
|
49
|
+
activesupport (>= 3.0, < 4.1)
|
|
50
|
+
diff-lcs (1.2.5)
|
|
51
|
+
docile (1.1.3)
|
|
52
|
+
erubis (2.7.0)
|
|
53
|
+
hike (1.2.3)
|
|
54
|
+
i18n (0.6.9)
|
|
55
|
+
json (1.8.1)
|
|
56
|
+
mail (2.5.4)
|
|
57
|
+
mime-types (~> 1.16)
|
|
58
|
+
treetop (~> 1.4.8)
|
|
59
|
+
mime-types (1.25.1)
|
|
60
|
+
minitest (4.7.5)
|
|
61
|
+
mono_logger (1.1.0)
|
|
62
|
+
multi_json (1.9.0)
|
|
63
|
+
polyglot (0.3.4)
|
|
64
|
+
rack (1.5.2)
|
|
65
|
+
rack-protection (1.5.2)
|
|
66
|
+
rack
|
|
67
|
+
rack-test (0.6.2)
|
|
68
|
+
rack (>= 1.0)
|
|
69
|
+
rails (4.0.4)
|
|
70
|
+
actionmailer (= 4.0.4)
|
|
71
|
+
actionpack (= 4.0.4)
|
|
72
|
+
activerecord (= 4.0.4)
|
|
73
|
+
activesupport (= 4.0.4)
|
|
74
|
+
bundler (>= 1.3.0, < 2.0)
|
|
75
|
+
railties (= 4.0.4)
|
|
76
|
+
sprockets-rails (~> 2.0.0)
|
|
77
|
+
railties (4.0.4)
|
|
78
|
+
actionpack (= 4.0.4)
|
|
79
|
+
activesupport (= 4.0.4)
|
|
80
|
+
rake (>= 0.8.7)
|
|
81
|
+
thor (>= 0.18.1, < 2.0)
|
|
82
|
+
rake (10.1.1)
|
|
83
|
+
redis (3.0.7)
|
|
84
|
+
redis-namespace (1.4.1)
|
|
85
|
+
redis (~> 3.0.4)
|
|
86
|
+
resque (1.25.1)
|
|
87
|
+
mono_logger (~> 1.0)
|
|
88
|
+
multi_json (~> 1.0)
|
|
89
|
+
redis-namespace (~> 1.2)
|
|
90
|
+
sinatra (>= 0.9.2)
|
|
91
|
+
vegas (~> 0.1.2)
|
|
92
|
+
rspec (2.14.1)
|
|
93
|
+
rspec-core (~> 2.14.0)
|
|
94
|
+
rspec-expectations (~> 2.14.0)
|
|
95
|
+
rspec-mocks (~> 2.14.0)
|
|
96
|
+
rspec-core (2.14.7)
|
|
97
|
+
rspec-expectations (2.14.5)
|
|
98
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
|
99
|
+
rspec-mocks (2.14.6)
|
|
100
|
+
rspec-sidekiq (1.0.0)
|
|
101
|
+
rspec (>= 2.0.0)
|
|
102
|
+
sidekiq (>= 2.4.0)
|
|
103
|
+
sidekiq (2.17.6)
|
|
104
|
+
celluloid (>= 0.15.2)
|
|
105
|
+
connection_pool (>= 1.0.0)
|
|
106
|
+
json
|
|
107
|
+
redis (>= 3.0.6)
|
|
108
|
+
redis-namespace (>= 1.3.1)
|
|
109
|
+
simplecov (0.8.2)
|
|
110
|
+
docile (~> 1.1.0)
|
|
111
|
+
multi_json
|
|
112
|
+
simplecov-html (~> 0.8.0)
|
|
113
|
+
simplecov-html (0.8.0)
|
|
114
|
+
sinatra (1.4.4)
|
|
115
|
+
rack (~> 1.4)
|
|
116
|
+
rack-protection (~> 1.4)
|
|
117
|
+
tilt (~> 1.3, >= 1.3.4)
|
|
118
|
+
sprockets (2.12.0)
|
|
119
|
+
hike (~> 1.2)
|
|
120
|
+
multi_json (~> 1.0)
|
|
121
|
+
rack (~> 1.0)
|
|
122
|
+
tilt (~> 1.1, != 1.3.0)
|
|
123
|
+
sprockets-rails (2.0.1)
|
|
124
|
+
actionpack (>= 3.0)
|
|
125
|
+
activesupport (>= 3.0)
|
|
126
|
+
sprockets (~> 2.8)
|
|
127
|
+
thor (0.18.1)
|
|
128
|
+
thread_safe (0.2.0)
|
|
129
|
+
atomic (>= 1.1.7, < 2)
|
|
130
|
+
tilt (1.4.1)
|
|
131
|
+
timecop (0.7.1)
|
|
132
|
+
timers (1.1.0)
|
|
133
|
+
treetop (1.4.15)
|
|
134
|
+
polyglot
|
|
135
|
+
polyglot (>= 0.3.1)
|
|
136
|
+
tzinfo (0.3.39)
|
|
137
|
+
vegas (0.1.11)
|
|
138
|
+
rack (>= 1.0.0)
|
|
139
|
+
|
|
140
|
+
PLATFORMS
|
|
141
|
+
ruby
|
|
142
|
+
|
|
143
|
+
DEPENDENCIES
|
|
144
|
+
codeclimate-test-reporter
|
|
145
|
+
debugger
|
|
146
|
+
delayed_cron!
|
|
147
|
+
delayed_job
|
|
148
|
+
rails
|
|
149
|
+
resque
|
|
150
|
+
rspec
|
|
151
|
+
rspec-sidekiq
|
|
152
|
+
sidekiq
|
|
153
|
+
timecop
|
data/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
[](https://travis-ci.org/sellect/delayed_cron)
|
|
2
|
+
[](https://codeclimate.com/github/sellect/delayed_cron)
|
|
3
|
+
|
|
4
|
+
# DelayedCron
|
|
5
|
+
run cron jobs with sidekiq, delayed_job, or resque
|
|
6
|
+
|
|
7
|
+
### DEPENDENCIES:
|
|
8
|
+
- background process handler: sidekiq, delayed_job, or resque
|
|
9
|
+
|
|
10
|
+
### INSTALL
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
gem "delayed_cron", git: "git@github.com:sellect/delayed_cron", tag: "v0.1.0"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### USE IN MODEL
|
|
17
|
+
```ruby
|
|
18
|
+
class Product < ActiveRecord::Base
|
|
19
|
+
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
# Define in Model
|
|
23
|
+
# * this is an alternative to the methods array in config
|
|
24
|
+
#
|
|
25
|
+
# OPTIONS: *optional
|
|
26
|
+
# - interval - override default_inteveral from setup
|
|
27
|
+
# - at - set time of day the cron should be run, timezone and seconds are optional
|
|
28
|
+
cron_job :some_method_to_run_as_cron, interval: 3.days, at: "00:00:00 -0400"
|
|
29
|
+
|
|
30
|
+
def self.some_method_to_run_as_cron
|
|
31
|
+
# this method will be run every 15 minutes
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### CONFIGURE
|
|
40
|
+
```ruby
|
|
41
|
+
DelayedCron.setup do |config|
|
|
42
|
+
|
|
43
|
+
# default interval to run cron jobs
|
|
44
|
+
config.default_interval = 10.minutes
|
|
45
|
+
|
|
46
|
+
# array of methods to run at the above configured interval
|
|
47
|
+
config.cron_jobs = [ "SomeClass.expensive_task", "AnotherClass.other_expensive_task" ]
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### NOTES:
|
|
53
|
+
|
|
54
|
+
- when using with sidekiq and rails there can be a config/initializer load order issue. Below is a fix to insure sidekiq is loaded first
|
|
55
|
+
```ruby
|
|
56
|
+
Rails.application.config.after_initialize do
|
|
57
|
+
DelayedCron.setup do |config|
|
|
58
|
+
...
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
|
+
This initializes dealyed cron after all other initializers have loaded.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
### TO DO:
|
|
66
|
+
- add support for Resque
|
data/Rakefile
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
2
|
+
require "delayed_cron/version"
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = %q{delayed_cron}
|
|
6
|
+
s.version = DelayedCron::VERSION
|
|
7
|
+
|
|
8
|
+
s.authors = ["Justin Grubbs"]
|
|
9
|
+
s.summary = %q{Run your cron jobs with sidekiq, delayed_job, or resque.}
|
|
10
|
+
s.description = %q{Run your cron jobs with sidekiq, delayed_job, or resque.}
|
|
11
|
+
s.email = %q{justin@sellect.com}
|
|
12
|
+
s.homepage = %q{http://github.com/sellect/delayed_cron}
|
|
13
|
+
|
|
14
|
+
s.add_development_dependency "delayed_job"
|
|
15
|
+
s.add_development_dependency "resque"
|
|
16
|
+
s.add_development_dependency "sidekiq"
|
|
17
|
+
s.add_development_dependency "rspec"
|
|
18
|
+
s.add_development_dependency "rails"
|
|
19
|
+
s.add_development_dependency "debugger"
|
|
20
|
+
s.add_development_dependency "timecop"
|
|
21
|
+
s.add_development_dependency "rspec-sidekiq"
|
|
22
|
+
s.add_development_dependency "codeclimate-test-reporter"
|
|
23
|
+
|
|
24
|
+
s.files = `git ls-files`.split("\n")
|
|
25
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
26
|
+
end
|
data/init.rb
ADDED
data/lib/delayed_cron.rb
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'delayed_cron/jobs'
|
|
2
|
+
require 'delayed_cron/railtie'
|
|
3
|
+
|
|
4
|
+
module DelayedCron
|
|
5
|
+
|
|
6
|
+
mattr_accessor :default_interval, :cron_jobs
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
|
|
10
|
+
def setup
|
|
11
|
+
yield self
|
|
12
|
+
define_cron_jobs
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def define_cron_jobs
|
|
16
|
+
return false unless cron_jobs.present?
|
|
17
|
+
cron_jobs.each do |job|
|
|
18
|
+
klass, name = job.split(".")
|
|
19
|
+
# TODO: raise error if interval is not set from config
|
|
20
|
+
DelayedCron.schedule(klass, name, { interval: default_interval })
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def processor
|
|
25
|
+
return DelayedCron::Jobs::DelayedJob if defined? ::Delayed::Job
|
|
26
|
+
return DelayedCron::Jobs::Resque if defined? ::Resque
|
|
27
|
+
return DelayedCron::Jobs::Sidekiq if defined? ::Sidekiq
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def schedule(klass, method_name, options)
|
|
31
|
+
if options[:at]
|
|
32
|
+
options[:interval] = adjust_interval(beginning_of_day(options[:interval].to_i), options[:at])
|
|
33
|
+
end
|
|
34
|
+
processor.enqueue_delayed_cron(klass, method_name, options)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def process_job(klass, method_name, options)
|
|
38
|
+
# TODO: add ability to send args to klass method
|
|
39
|
+
klass.constantize.send(method_name)
|
|
40
|
+
schedule(klass, method_name, options)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def beginning_of_day(seconds)
|
|
44
|
+
(Time.now + seconds).beginning_of_day
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def adjust_interval(date, time_string)
|
|
48
|
+
time = parse_time(time_string)
|
|
49
|
+
adjusted_date = DateTime.civil(date.year, date.month, date.day, time[:hours], time[:mins], time[:secs], Rational(time[:tz], 2400))
|
|
50
|
+
adjusted_date.to_i - Time.now.to_i
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def parse_time(string)
|
|
54
|
+
time_array = string.split(/:|\ /).map(&:to_i)
|
|
55
|
+
time = {
|
|
56
|
+
hours: time_array[0], mins: time_array[1],
|
|
57
|
+
secs: time_array[2] || 0, tz: time_array[3] || Time.now.strftime("%z").to_i
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
module Glue
|
|
64
|
+
def self.included(base)
|
|
65
|
+
base.extend(ClassMethods)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
module ClassMethods
|
|
70
|
+
|
|
71
|
+
def cron_job(name, options = { interval: DelayedCron.default_interval })
|
|
72
|
+
DelayedCron.schedule(self.name.to_s, name, options)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'delayed_job'
|
|
2
|
+
|
|
3
|
+
module DelayedCron
|
|
4
|
+
module Jobs
|
|
5
|
+
class DelayedJob < Struct.new(:klass, :method_name, :options)
|
|
6
|
+
|
|
7
|
+
def self.enqueue_delayed_cron(klass, method_name, options)
|
|
8
|
+
unless scheduled?(klass, method_name)
|
|
9
|
+
options.symbolize_keys!
|
|
10
|
+
::Delayed::Job.enqueue(
|
|
11
|
+
:payload_object => new(klass, method_name, options),
|
|
12
|
+
:run_at => Time.now + options[:interval],
|
|
13
|
+
:queue => :cron_job
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.scheduled?(klass, method_name)
|
|
19
|
+
::Delayed::Job.all.each do |job|
|
|
20
|
+
obj = YAML.load(job.handler)
|
|
21
|
+
scheduled = true if obj["object"] == klass && obj["method_name"] == method_name.to_s
|
|
22
|
+
end
|
|
23
|
+
scheduled ||= false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def perform(klass, method_name, options)
|
|
27
|
+
DelayedCron.process_job(klass, method_name, options)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'resque'
|
|
2
|
+
|
|
3
|
+
module DelayedCron
|
|
4
|
+
module Jobs
|
|
5
|
+
class Resque
|
|
6
|
+
@queue = :cron_job
|
|
7
|
+
|
|
8
|
+
def self.enqueue_delayed_cron(klass, method_name, options)
|
|
9
|
+
unless scheduled?(klass, method_name)
|
|
10
|
+
# TODO: need to find resque's equivalent to sidekiq's perform_in method
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.scheduled?(klass, method_name)
|
|
15
|
+
# TODO: returns true if job is already scheduled
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.perform(klass, method_name, options)
|
|
19
|
+
DelayedCron.process_job(klass, method_name, options)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'sidekiq/worker'
|
|
2
|
+
|
|
3
|
+
module DelayedCron
|
|
4
|
+
module Jobs
|
|
5
|
+
class Sidekiq
|
|
6
|
+
include ::Sidekiq::Worker
|
|
7
|
+
sidekiq_options :queue => :cron_job
|
|
8
|
+
|
|
9
|
+
def self.enqueue_delayed_cron(klass, method_name, options)
|
|
10
|
+
unless scheduled?(klass, method_name)
|
|
11
|
+
options.symbolize_keys!
|
|
12
|
+
perform_in(options[:interval], klass, method_name, options)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.scheduled?(klass, method_name)
|
|
17
|
+
items = []
|
|
18
|
+
::Sidekiq::ScheduledSet.new.each { |job| items << job.item }
|
|
19
|
+
items.select do |item|
|
|
20
|
+
item["args"][0] == klass &&
|
|
21
|
+
item["args"][1] == method_name.to_s
|
|
22
|
+
end.present?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def perform(klass, method_name, options)
|
|
26
|
+
DelayedCron.process_job(klass, method_name, options)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'delayed_cron'
|
|
2
|
+
|
|
3
|
+
module DelayedCron
|
|
4
|
+
|
|
5
|
+
if defined? Rails::Railtie
|
|
6
|
+
require 'rails'
|
|
7
|
+
|
|
8
|
+
# On initialzation, include DelayedCron
|
|
9
|
+
class Railtie < Rails::Railtie
|
|
10
|
+
initializer 'delayed_cron.insert_into_active_record' do
|
|
11
|
+
ActiveSupport.on_load :active_record do
|
|
12
|
+
DelayedCron::Railtie.insert
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class Railtie
|
|
19
|
+
|
|
20
|
+
# Glue includes DelayedCron Class Methods into ActiveRecord
|
|
21
|
+
def self.insert
|
|
22
|
+
ActiveRecord::Base.send(:include, DelayedCron::Glue)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
data/rails/init.rb
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'timecop'
|
|
3
|
+
require 'rspec-sidekiq'
|
|
4
|
+
|
|
5
|
+
describe DelayedCron do
|
|
6
|
+
|
|
7
|
+
describe ".setup" do
|
|
8
|
+
|
|
9
|
+
it "yields self" do
|
|
10
|
+
DelayedCron.setup do |config|
|
|
11
|
+
DelayedCron.should == config
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "sends cron jobs to define_cron_jobs" do
|
|
16
|
+
DelayedCron.should_receive(:define_cron_jobs)
|
|
17
|
+
setup(default_interval: 1.hour)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe ".define_cron_jobs" do
|
|
23
|
+
|
|
24
|
+
it "should have a default_interval" do
|
|
25
|
+
setup(default_interval: 1.hour)
|
|
26
|
+
DelayedCron.default_interval.should_not be_nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should have an array of cron_jobs" do
|
|
30
|
+
setup(default_interval: 1.hour)
|
|
31
|
+
DelayedCron.cron_jobs.should be_an(Array)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "sends cron_jobs to schedule" do
|
|
35
|
+
options = { default_interval: 1.hour, cron_jobs: ["SomeClass.long_method", "AnotherClass.expensive_method"] }
|
|
36
|
+
options[:cron_jobs].each do |cron_job|
|
|
37
|
+
klass, method_name = cron_job.split(".")
|
|
38
|
+
DelayedCron.should_receive(:schedule).with(klass, method_name, { interval: options[:default_interval] })
|
|
39
|
+
end
|
|
40
|
+
setup(options)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe ".processor" do
|
|
46
|
+
|
|
47
|
+
it "returns processor" do
|
|
48
|
+
DelayedCron.processor.should == DelayedCron::Jobs::Sidekiq
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe ".schedule" do
|
|
54
|
+
it "schedules cron jobs" do
|
|
55
|
+
DelayedCron.schedule("SomeClass", "long_method", { interval: 1.hour })
|
|
56
|
+
expect(DelayedCron.processor).to be_processed_in :cron_job
|
|
57
|
+
expect(DelayedCron.processor).to have(1).jobs
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe ".process_job" do
|
|
62
|
+
|
|
63
|
+
it "should call the cron jobs method" do
|
|
64
|
+
klass = build_class("SomeClass", "long_method", {})
|
|
65
|
+
klass.should_receive(:long_method)
|
|
66
|
+
DelayedCron.process_job(klass.name, "long_method", {})
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "should reschedule the cron job after processing" do
|
|
70
|
+
klass, name = "SomeClass", "test_method"
|
|
71
|
+
build_class(klass, name)
|
|
72
|
+
DelayedCron.should_receive(:schedule).with.with(klass, name, {})
|
|
73
|
+
DelayedCron.process_job(klass, name, {})
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe ".beginning_of_day" do
|
|
79
|
+
it "returns the beginning of the day for the interval" do
|
|
80
|
+
seconds = 2.days.to_i
|
|
81
|
+
beginning_of_day_2_days_from_now = DelayedCron.beginning_of_day(seconds)
|
|
82
|
+
expect(beginning_of_day_2_days_from_now).to be < 2.days.from_now
|
|
83
|
+
expect(beginning_of_day_2_days_from_now).to be > 1.day.from_now
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe ".adjust_interval" do
|
|
88
|
+
it "adjusts the interval based on the :at option" do
|
|
89
|
+
# Set Time.now to January 1, 2014 12:00:00 PM
|
|
90
|
+
Timecop.freeze(Time.local(2014, 1, 1, 12, 0, 0))
|
|
91
|
+
interval = 9.days
|
|
92
|
+
adjusted_interval = interval - 12.hours
|
|
93
|
+
DelayedCron.processor.should_receive(:enqueue_delayed_cron)
|
|
94
|
+
.with("SomeClass", "long_method", { interval: adjusted_interval.to_i, at: "00:00" })
|
|
95
|
+
DelayedCron.schedule("SomeClass", "long_method", { interval: interval, at: "00:00" })
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
describe "cron_job" do
|
|
100
|
+
it "schedules cron jobs found in a model" do
|
|
101
|
+
klass, name = "SomeClass", "some_method"
|
|
102
|
+
DelayedCron.should_receive(:schedule).with(klass, name, {})
|
|
103
|
+
build_class(klass, name)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'codeclimate-test-reporter'
|
|
2
|
+
CodeClimate::TestReporter.start
|
|
3
|
+
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
Bundler.setup
|
|
6
|
+
|
|
7
|
+
require 'rails'
|
|
8
|
+
require 'active_record'
|
|
9
|
+
require 'timecop'
|
|
10
|
+
require 'sidekiq'
|
|
11
|
+
require 'rspec-sidekiq'
|
|
12
|
+
|
|
13
|
+
require 'delayed_cron/railtie'
|
|
14
|
+
DelayedCron::Railtie.insert
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
RSpec.configure do |config|
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def setup(options)
|
|
22
|
+
DelayedCron.setup do |config|
|
|
23
|
+
config.default_interval = options[:default_interval]
|
|
24
|
+
config.cron_jobs = options[:cron_jobs] || []
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def build_class(class_name, name, options = {})
|
|
29
|
+
# setup class and include delayed_cron
|
|
30
|
+
|
|
31
|
+
ActiveRecord::Base.send(:include, DelayedCron::Glue)
|
|
32
|
+
Object.send(:remove_const, class_name) rescue nil
|
|
33
|
+
|
|
34
|
+
# Set class as a constant
|
|
35
|
+
klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
|
|
36
|
+
|
|
37
|
+
# Setup class with paperclip and delayed paperclip
|
|
38
|
+
klass.class_eval do
|
|
39
|
+
include DelayedCron::Glue
|
|
40
|
+
|
|
41
|
+
cron_job name, options
|
|
42
|
+
|
|
43
|
+
def self.test_method
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
klass
|
|
49
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: delayed_cron
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Justin Grubbs
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-03-31 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: delayed_job
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - '>='
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - '>='
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: resque
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - '>='
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - '>='
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: sidekiq
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - '>='
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - '>='
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rspec
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - '>='
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rails
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - '>='
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - '>='
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: debugger
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - '>='
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - '>='
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: timecop
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - '>='
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - '>='
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rspec-sidekiq
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - '>='
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - '>='
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: codeclimate-test-reporter
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - '>='
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - '>='
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0'
|
|
139
|
+
description: Run your cron jobs with sidekiq, delayed_job, or resque.
|
|
140
|
+
email: justin@sellect.com
|
|
141
|
+
executables: []
|
|
142
|
+
extensions: []
|
|
143
|
+
extra_rdoc_files: []
|
|
144
|
+
files:
|
|
145
|
+
- .gitignore
|
|
146
|
+
- .rspec
|
|
147
|
+
- .ruby-version
|
|
148
|
+
- .travis.yml
|
|
149
|
+
- Gemfile
|
|
150
|
+
- Gemfile.lock
|
|
151
|
+
- README.md
|
|
152
|
+
- Rakefile
|
|
153
|
+
- delayed_cron.gemspec
|
|
154
|
+
- init.rb
|
|
155
|
+
- lib/delayed_cron.rb
|
|
156
|
+
- lib/delayed_cron/jobs.rb
|
|
157
|
+
- lib/delayed_cron/jobs/delayed_job.rb
|
|
158
|
+
- lib/delayed_cron/jobs/resque.rb
|
|
159
|
+
- lib/delayed_cron/jobs/sidekiq.rb
|
|
160
|
+
- lib/delayed_cron/railtie.rb
|
|
161
|
+
- lib/delayed_cron/version.rb
|
|
162
|
+
- rails/init.rb
|
|
163
|
+
- spec/delayed_cron_spec.rb
|
|
164
|
+
- spec/spec_helper.rb
|
|
165
|
+
homepage: http://github.com/sellect/delayed_cron
|
|
166
|
+
licenses: []
|
|
167
|
+
metadata: {}
|
|
168
|
+
post_install_message:
|
|
169
|
+
rdoc_options: []
|
|
170
|
+
require_paths:
|
|
171
|
+
- lib
|
|
172
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
173
|
+
requirements:
|
|
174
|
+
- - '>='
|
|
175
|
+
- !ruby/object:Gem::Version
|
|
176
|
+
version: '0'
|
|
177
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
178
|
+
requirements:
|
|
179
|
+
- - '>='
|
|
180
|
+
- !ruby/object:Gem::Version
|
|
181
|
+
version: '0'
|
|
182
|
+
requirements: []
|
|
183
|
+
rubyforge_project:
|
|
184
|
+
rubygems_version: 2.2.2
|
|
185
|
+
signing_key:
|
|
186
|
+
specification_version: 4
|
|
187
|
+
summary: Run your cron jobs with sidekiq, delayed_job, or resque.
|
|
188
|
+
test_files:
|
|
189
|
+
- spec/delayed_cron_spec.rb
|
|
190
|
+
- spec/spec_helper.rb
|