roqua-support 0.1.26 → 0.1.27
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile.lock +3 -0
- data/README.md +29 -0
- data/lib/roqua-support.rb +10 -0
- data/lib/roqua-support/railtie.rb +16 -0
- data/lib/roqua-support/version.rb +1 -1
- data/lib/roqua/probes/scheduling_probe.rb +15 -0
- data/lib/roqua/scheduling/cron_job.rb +3 -0
- data/lib/roqua/scheduling/cron_job_table.rb +12 -0
- data/lib/roqua/scheduling/schedule.rb +34 -0
- data/lib/roqua/scheduling/scheduler.rb +47 -0
- data/lib/roqua/scheduling/task.rb +23 -0
- data/roqua-support.gemspec +4 -3
- data/spec/roqua/scheduling/scheduler_spec.rb +106 -0
- data/spec/spec_helper.rb +6 -4
- metadata +53 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4bda6e60469417b289cc6b362240df7943ef3a32
|
4
|
+
data.tar.gz: 8b5a13cfbeddc4eb24f7d1cca3fe5c828df019c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8dbd51457aa872e2684042494741aadc952814266fde183c09a7bf48f8a6d969df495fe3f708c39aa5d6fb3d4ecbcf6ad716037177b69fe65b3da5b205ec60e2
|
7
|
+
data.tar.gz: 7f39013acd584c9faead2d9475c0f8ed8fc74b455b4eb621a0596a2fef41482f0b59b7e5fa41c7bb0b8757ed2f1c44bd24875f6bfcc0b02b9084bdca23851779
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -12,6 +12,7 @@ PATH
|
|
12
12
|
active_interaction (~> 3.0)
|
13
13
|
activesupport (>= 3.2, < 6)
|
14
14
|
naught (~> 1.0)
|
15
|
+
with_advisory_lock (~> 3.2)
|
15
16
|
|
16
17
|
GEM
|
17
18
|
remote: https://rubygems.org/
|
@@ -168,6 +169,8 @@ GEM
|
|
168
169
|
tzinfo (1.2.2)
|
169
170
|
thread_safe (~> 0.1)
|
170
171
|
unicode-display_width (1.3.0)
|
172
|
+
with_advisory_lock (3.2.0)
|
173
|
+
activerecord (>= 3.2)
|
171
174
|
|
172
175
|
PLATFORMS
|
173
176
|
ruby
|
data/README.md
CHANGED
@@ -110,6 +110,35 @@ Enable it in a project by calling:
|
|
110
110
|
Roqua::Probes::DelayedJobProbe.enable
|
111
111
|
```
|
112
112
|
|
113
|
+
# Scheduling
|
114
|
+
|
115
|
+
For running code in a recurring fashion (for example hourly or daily) a scheduling mechanism is included in roqua-support.
|
116
|
+
|
117
|
+
To configure the jobs that need to run you need to create the file `config/schedule.rb` in the Rails project that you want
|
118
|
+
to schedule jobs for. An example configuration:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
Roqua::Scheduling::Schedule.setup do |cron|
|
122
|
+
cron.add_task 'hourly', run_at: Roqua::Scheduling::Schedule::BEGINNING_OF_EVERY_HOUR do
|
123
|
+
# Put code here that you want to run at the first minute of every hour
|
124
|
+
end
|
125
|
+
|
126
|
+
cron.add_task 'daily', run_at: Roqua::Scheduling::Schedule::BEGINNING_OF_EVERY_DAY do
|
127
|
+
# Put code here that you want to run every day at 0:00
|
128
|
+
end
|
129
|
+
|
130
|
+
cron.add_task 'every_10_minutes', run_at: proc { 10.minutes.from_now } do
|
131
|
+
# Put code here that you want to approximately run every 10 minutes. Because the run_at is calculated after a job
|
132
|
+
# is finished the time between jobs will be 10 minutes plus the time the job itself takes.
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
Normally the RoQua infrastructure should be prepared so the jobs automatically are run if the application is correctly
|
138
|
+
deployed. An AppSignal probe can be used as a fallback for job triggering. It can be enabled by placing the following
|
139
|
+
code in a Rails initializer:
|
140
|
+
`Roqua::Probes::SchedulingProbe.enable`
|
141
|
+
|
113
142
|
### ActiveInteraction extensions
|
114
143
|
|
115
144
|
```
|
data/lib/roqua-support.rb
CHANGED
@@ -1,13 +1,23 @@
|
|
1
1
|
require "roqua-support/version"
|
2
|
+
require "roqua-support/railtie" if defined?(Rails)
|
2
3
|
require "roqua/support"
|
3
4
|
|
4
5
|
module Roqua
|
5
6
|
module Probes
|
6
7
|
autoload :DelayedJobProbe, 'roqua/probes/delayed_job_probe'
|
8
|
+
autoload :SchedulingProbe, 'roqua/probes/scheduling_probe'
|
7
9
|
end
|
8
10
|
|
9
11
|
module Responders
|
10
12
|
autoload :ApiErrorsResponder, 'roqua/responders/api_errors_responder'
|
11
13
|
autoload :ActiveInteractionAwareResponder, 'roqua/responders/active_interaction_aware_responder'
|
12
14
|
end
|
15
|
+
|
16
|
+
module Scheduling
|
17
|
+
autoload :CronJob, 'roqua/scheduling/cron_job'
|
18
|
+
autoload :CronJobTable, 'roqua/scheduling/cron_job_table'
|
19
|
+
autoload :Scheduler, 'roqua/scheduling/scheduler'
|
20
|
+
autoload :Schedule, 'roqua/scheduling/schedule'
|
21
|
+
autoload :Task, 'roqua/scheduling/task'
|
22
|
+
end
|
13
23
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Roqua
|
2
|
+
# Include global rake tasks
|
3
|
+
class Railtie < Rails::Railtie
|
4
|
+
rake_tasks do
|
5
|
+
namespace :roqua do
|
6
|
+
desc 'Check if cron needs to run on this instance of the application'
|
7
|
+
task :cron_ping do
|
8
|
+
ActiveRecord::Base.establish_connection
|
9
|
+
require_relative Rails.root.join('config', 'schedule.rb')
|
10
|
+
Roqua::Scheduling::Scheduler.new.ping
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'base_probe'
|
2
|
+
|
3
|
+
module Roqua
|
4
|
+
module Probes
|
5
|
+
class SchedulingProbe
|
6
|
+
extend BaseProbe
|
7
|
+
|
8
|
+
def call
|
9
|
+
ActiveRecord::Base.establish_connection
|
10
|
+
require_relative Rails.root.join('config', 'schedule.rb')
|
11
|
+
Roqua::Scheduling::Scheduler.new.ping
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Roqua::Scheduling::CronJobTable
|
2
|
+
def self.create_cron_jobs_table(schema)
|
3
|
+
schema.create_table :roqua_scheduling_cron_jobs, force: true do |t|
|
4
|
+
t.string :name, null: false
|
5
|
+
t.datetime :next_run_at, null: false
|
6
|
+
t.datetime :completed_at
|
7
|
+
t.timestamps null: false
|
8
|
+
end
|
9
|
+
|
10
|
+
schema.add_index :roqua_scheduling_cron_jobs, :name, unique: true
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Roqua::Scheduling::Schedule
|
2
|
+
attr_reader :tasks
|
3
|
+
|
4
|
+
BEGINNING_OF_EVERY_DAY = proc { Time.now.beginning_of_day + 1.day }
|
5
|
+
BEGINNING_OF_EVERY_HOUR = proc { Time.now.beginning_of_hour + 1.hour }
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@tasks = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_task(name, options, &block)
|
12
|
+
@tasks[name] = Roqua::Scheduling::Task.new(name, options, block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.setup
|
16
|
+
@schedule = Roqua::Scheduling::Schedule.new.tap do |new_schedule|
|
17
|
+
yield(new_schedule)
|
18
|
+
new_schedule.initialize_cronjob_table
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.current_schedule
|
23
|
+
@schedule ||= Roqua::Scheduling::Schedule.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize_cronjob_table
|
27
|
+
Roqua::Scheduling::CronJob.where('name NOT IN (?)', tasks.values.map(&:name)).delete_all
|
28
|
+
|
29
|
+
tasks.each_value do |task|
|
30
|
+
cron_job = Roqua::Scheduling::CronJob.find_or_initialize_by(name: task.name)
|
31
|
+
cron_job.update next_run_at: task.next_run_at unless cron_job.persisted?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'with_advisory_lock'
|
2
|
+
|
3
|
+
class Roqua::Scheduling::Scheduler
|
4
|
+
def ping
|
5
|
+
with_advisory_lock do
|
6
|
+
jobs_to_run.each do |cron_job|
|
7
|
+
begin
|
8
|
+
run_task cron_job
|
9
|
+
rescue Exception => ex
|
10
|
+
Roqua::Support::Errors.report(ex)
|
11
|
+
raise ex if Rails.env.test?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def jobs_to_run
|
18
|
+
Roqua::Scheduling::CronJob.where('next_run_at <= ?', Time.now)
|
19
|
+
end
|
20
|
+
|
21
|
+
def tasks
|
22
|
+
schedule.tasks
|
23
|
+
end
|
24
|
+
|
25
|
+
def schedule
|
26
|
+
Roqua::Scheduling::Schedule.current_schedule
|
27
|
+
end
|
28
|
+
|
29
|
+
def advisory_lock_name
|
30
|
+
"#{ActiveRecord::Base.connection_config[:database]}_cron_lock"
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def with_advisory_lock
|
36
|
+
ActiveRecord::Base.with_advisory_lock(advisory_lock_name, timeout_seconds: 0) do
|
37
|
+
yield
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def run_task(cron_job)
|
42
|
+
task = schedule.tasks[cron_job.name]
|
43
|
+
task.run
|
44
|
+
|
45
|
+
cron_job.update completed_at: Time.now, next_run_at: task.next_run_at
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Roqua::Scheduling
|
2
|
+
class Task
|
3
|
+
attr_reader :name, :options
|
4
|
+
|
5
|
+
def initialize(name, options, callback)
|
6
|
+
@name = name
|
7
|
+
@options = options
|
8
|
+
@callback = callback
|
9
|
+
end
|
10
|
+
|
11
|
+
def run_at
|
12
|
+
options[:run_at]
|
13
|
+
end
|
14
|
+
|
15
|
+
def next_run_at
|
16
|
+
run_at.call
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
@callback.call
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/roqua-support.gemspec
CHANGED
@@ -18,15 +18,16 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
|
21
|
+
gem.add_dependency 'active_interaction', '~> 3.0'
|
21
22
|
gem.add_dependency 'activesupport', '>= 3.2', '< 6'
|
22
23
|
gem.add_dependency 'naught', '~> 1.0'
|
23
|
-
gem.add_dependency '
|
24
|
+
gem.add_dependency 'with_advisory_lock', '~> 3.2'
|
24
25
|
|
26
|
+
gem.add_development_dependency 'appsignal', '>= 2.3.1'
|
25
27
|
gem.add_development_dependency 'bundler', '~> 1.0'
|
28
|
+
gem.add_development_dependency 'delayed_job_active_record'
|
26
29
|
gem.add_development_dependency 'rake'
|
27
30
|
gem.add_development_dependency 'rspec', '>= 2.12.0', '< 4.0'
|
28
|
-
gem.add_development_dependency 'appsignal', '>= 2.3.1'
|
29
|
-
gem.add_development_dependency 'delayed_job_active_record'
|
30
31
|
gem.add_development_dependency 'sqlite3'
|
31
32
|
gem.add_development_dependency 'timecop'
|
32
33
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timecop'
|
3
|
+
|
4
|
+
describe Roqua::Scheduling::Scheduler do
|
5
|
+
before do
|
6
|
+
Timecop.freeze
|
7
|
+
Roqua::Scheduling::CronJob.delete_all
|
8
|
+
end
|
9
|
+
|
10
|
+
after { Timecop.return }
|
11
|
+
|
12
|
+
subject { described_class.new }
|
13
|
+
|
14
|
+
def setup_daily_and_hourly_schedule
|
15
|
+
Roqua::Scheduling::Schedule.setup do |cron|
|
16
|
+
cron.add_task 'hourly', run_at: Roqua::Scheduling::Schedule::BEGINNING_OF_EVERY_HOUR do
|
17
|
+
end
|
18
|
+
|
19
|
+
cron.add_task 'daily', run_at: Roqua::Scheduling::Schedule::BEGINNING_OF_EVERY_DAY do
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup_hourly_schedule
|
25
|
+
Roqua::Scheduling::Schedule.setup do |cron|
|
26
|
+
cron.add_task 'hourly', run_at: Roqua::Scheduling::Schedule::BEGINNING_OF_EVERY_HOUR do
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'creates the correct table rows' do
|
32
|
+
expect { setup_daily_and_hourly_schedule }
|
33
|
+
.to change { Roqua::Scheduling::CronJob.all.pluck(:name, :next_run_at, :completed_at) }
|
34
|
+
.from(
|
35
|
+
[]
|
36
|
+
)
|
37
|
+
.to(
|
38
|
+
[
|
39
|
+
['hourly', Time.now.beginning_of_hour + 1.hour, nil],
|
40
|
+
['daily', Time.now.beginning_of_day + 1.day, nil]
|
41
|
+
]
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'removes unused table rows' do
|
46
|
+
setup_daily_and_hourly_schedule
|
47
|
+
|
48
|
+
expect { setup_hourly_schedule }
|
49
|
+
.to change { Roqua::Scheduling::CronJob.all.pluck(:name).sort }
|
50
|
+
.from(['daily', 'hourly']).to(['hourly'])
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'generates a database specific advisory lock name' do
|
54
|
+
expect(ActiveRecord::Base.connection_config[:database]).to eql(':memory:')
|
55
|
+
expect(subject.advisory_lock_name).to eql ':memory:_cron_lock'
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'with a run_at in the future' do
|
59
|
+
before do
|
60
|
+
Roqua::Scheduling::Schedule.setup do |cron|
|
61
|
+
cron.add_task 'hourly', run_at: proc { 1.minute.from_now } do
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'the task will not be run' do
|
67
|
+
expect(subject.schedule.tasks['hourly']).to_not receive(:run)
|
68
|
+
subject.ping
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'callbacks' do
|
73
|
+
let(:callback_spy) { spy(:callback) }
|
74
|
+
|
75
|
+
it 'get executed' do
|
76
|
+
Roqua::Scheduling::Schedule.setup do |cron|
|
77
|
+
cron.add_task 'hourly', run_at: proc { 1.minute.ago } do
|
78
|
+
callback_spy.execute
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
expect(callback_spy).to receive(:execute)
|
83
|
+
subject.ping
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'when running multiple times' do
|
88
|
+
before do
|
89
|
+
Timecop.freeze(60.seconds.ago)
|
90
|
+
|
91
|
+
Roqua::Scheduling::Schedule.setup do |cron|
|
92
|
+
cron.add_task 'task', run_at: proc { 30.seconds.from_now } do
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
let(:schedule) { Roqua::Scheduling::Schedule.current_schedule }
|
98
|
+
|
99
|
+
it 'the task is only called once' do
|
100
|
+
expect(schedule.tasks['task']).to receive(:run).once
|
101
|
+
|
102
|
+
Timecop.return
|
103
|
+
3.times { Roqua::Scheduling::Scheduler.new.ping }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -19,9 +19,9 @@ ActiveRecord::Base.logger = Delayed::Worker.logger
|
|
19
19
|
ActiveRecord::Migration.verbose = false
|
20
20
|
|
21
21
|
ActiveRecord::Schema.define do
|
22
|
-
create_table :delayed_jobs, :
|
23
|
-
t.integer :priority, :
|
24
|
-
t.integer :attempts, :
|
22
|
+
create_table :delayed_jobs, force: true do |t|
|
23
|
+
t.integer :priority, default: 0
|
24
|
+
t.integer :attempts, default: 0
|
25
25
|
t.text :handler
|
26
26
|
t.text :last_error
|
27
27
|
t.datetime :run_at
|
@@ -33,5 +33,7 @@ ActiveRecord::Schema.define do
|
|
33
33
|
t.timestamps null: false
|
34
34
|
end
|
35
35
|
|
36
|
-
add_index :delayed_jobs, [:priority, :run_at], :
|
36
|
+
add_index :delayed_jobs, [:priority, :run_at], name: 'delayed_jobs_priority'
|
37
|
+
|
38
|
+
Roqua::Scheduling::CronJobTable.create_cron_jobs_table(self)
|
37
39
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roqua-support
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.27
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marten Veldthuis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: active_interaction
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: activesupport
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,95 +59,95 @@ dependencies:
|
|
45
59
|
- !ruby/object:Gem::Version
|
46
60
|
version: '1.0'
|
47
61
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
62
|
+
name: with_advisory_lock
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|
50
64
|
requirements:
|
51
65
|
- - "~>"
|
52
66
|
- !ruby/object:Gem::Version
|
53
|
-
version: '3.
|
67
|
+
version: '3.2'
|
54
68
|
type: :runtime
|
55
69
|
prerelease: false
|
56
70
|
version_requirements: !ruby/object:Gem::Requirement
|
57
71
|
requirements:
|
58
72
|
- - "~>"
|
59
73
|
- !ruby/object:Gem::Version
|
60
|
-
version: '3.
|
74
|
+
version: '3.2'
|
61
75
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
76
|
+
name: appsignal
|
63
77
|
requirement: !ruby/object:Gem::Requirement
|
64
78
|
requirements:
|
65
|
-
- - "
|
79
|
+
- - ">="
|
66
80
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
81
|
+
version: 2.3.1
|
68
82
|
type: :development
|
69
83
|
prerelease: false
|
70
84
|
version_requirements: !ruby/object:Gem::Requirement
|
71
85
|
requirements:
|
72
|
-
- - "
|
86
|
+
- - ">="
|
73
87
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
88
|
+
version: 2.3.1
|
75
89
|
- !ruby/object:Gem::Dependency
|
76
|
-
name:
|
90
|
+
name: bundler
|
77
91
|
requirement: !ruby/object:Gem::Requirement
|
78
92
|
requirements:
|
79
|
-
- - "
|
93
|
+
- - "~>"
|
80
94
|
- !ruby/object:Gem::Version
|
81
|
-
version: '0'
|
95
|
+
version: '1.0'
|
82
96
|
type: :development
|
83
97
|
prerelease: false
|
84
98
|
version_requirements: !ruby/object:Gem::Requirement
|
85
99
|
requirements:
|
86
|
-
- - "
|
100
|
+
- - "~>"
|
87
101
|
- !ruby/object:Gem::Version
|
88
|
-
version: '0'
|
102
|
+
version: '1.0'
|
89
103
|
- !ruby/object:Gem::Dependency
|
90
|
-
name:
|
104
|
+
name: delayed_job_active_record
|
91
105
|
requirement: !ruby/object:Gem::Requirement
|
92
106
|
requirements:
|
93
107
|
- - ">="
|
94
108
|
- !ruby/object:Gem::Version
|
95
|
-
version:
|
96
|
-
- - "<"
|
97
|
-
- !ruby/object:Gem::Version
|
98
|
-
version: '4.0'
|
109
|
+
version: '0'
|
99
110
|
type: :development
|
100
111
|
prerelease: false
|
101
112
|
version_requirements: !ruby/object:Gem::Requirement
|
102
113
|
requirements:
|
103
114
|
- - ">="
|
104
115
|
- !ruby/object:Gem::Version
|
105
|
-
version:
|
106
|
-
- - "<"
|
107
|
-
- !ruby/object:Gem::Version
|
108
|
-
version: '4.0'
|
116
|
+
version: '0'
|
109
117
|
- !ruby/object:Gem::Dependency
|
110
|
-
name:
|
118
|
+
name: rake
|
111
119
|
requirement: !ruby/object:Gem::Requirement
|
112
120
|
requirements:
|
113
121
|
- - ">="
|
114
122
|
- !ruby/object:Gem::Version
|
115
|
-
version:
|
123
|
+
version: '0'
|
116
124
|
type: :development
|
117
125
|
prerelease: false
|
118
126
|
version_requirements: !ruby/object:Gem::Requirement
|
119
127
|
requirements:
|
120
128
|
- - ">="
|
121
129
|
- !ruby/object:Gem::Version
|
122
|
-
version:
|
130
|
+
version: '0'
|
123
131
|
- !ruby/object:Gem::Dependency
|
124
|
-
name:
|
132
|
+
name: rspec
|
125
133
|
requirement: !ruby/object:Gem::Requirement
|
126
134
|
requirements:
|
127
135
|
- - ">="
|
128
136
|
- !ruby/object:Gem::Version
|
129
|
-
version:
|
137
|
+
version: 2.12.0
|
138
|
+
- - "<"
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '4.0'
|
130
141
|
type: :development
|
131
142
|
prerelease: false
|
132
143
|
version_requirements: !ruby/object:Gem::Requirement
|
133
144
|
requirements:
|
134
145
|
- - ">="
|
135
146
|
- !ruby/object:Gem::Version
|
136
|
-
version:
|
147
|
+
version: 2.12.0
|
148
|
+
- - "<"
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '4.0'
|
137
151
|
- !ruby/object:Gem::Dependency
|
138
152
|
name: sqlite3
|
139
153
|
requirement: !ruby/object:Gem::Requirement
|
@@ -186,6 +200,7 @@ files:
|
|
186
200
|
- gemfiles/rails42.gemfile
|
187
201
|
- gemfiles/rails50.gemfile
|
188
202
|
- lib/roqua-support.rb
|
203
|
+
- lib/roqua-support/railtie.rb
|
189
204
|
- lib/roqua-support/version.rb
|
190
205
|
- lib/roqua/core_ext/active_interaction/filters/date_time_as_unix_extension.rb
|
191
206
|
- lib/roqua/core_ext/active_interaction/filters/duration_filter.rb
|
@@ -197,8 +212,14 @@ files:
|
|
197
212
|
- lib/roqua/core_ext/fixnum/clamp.rb
|
198
213
|
- lib/roqua/probes/base_probe.rb
|
199
214
|
- lib/roqua/probes/delayed_job_probe.rb
|
215
|
+
- lib/roqua/probes/scheduling_probe.rb
|
200
216
|
- lib/roqua/responders/active_interaction_aware_responder.rb
|
201
217
|
- lib/roqua/responders/api_errors_responder.rb
|
218
|
+
- lib/roqua/scheduling/cron_job.rb
|
219
|
+
- lib/roqua/scheduling/cron_job_table.rb
|
220
|
+
- lib/roqua/scheduling/schedule.rb
|
221
|
+
- lib/roqua/scheduling/scheduler.rb
|
222
|
+
- lib/roqua/scheduling/task.rb
|
202
223
|
- lib/roqua/support.rb
|
203
224
|
- lib/roqua/support/command_runner.rb
|
204
225
|
- lib/roqua/support/errors.rb
|
@@ -220,6 +241,7 @@ files:
|
|
220
241
|
- spec/roqua/probes/delayed_job_probe_spec.rb
|
221
242
|
- spec/roqua/responders/active_interaction_aware_responder_spec.rb
|
222
243
|
- spec/roqua/responders/api_errors_responder_spec.rb
|
244
|
+
- spec/roqua/scheduling/scheduler_spec.rb
|
223
245
|
- spec/roqua/support/errors_spec.rb
|
224
246
|
- spec/roqua/support/helpers_spec.rb
|
225
247
|
- spec/roqua/support/logwrapper_spec.rb
|
@@ -265,6 +287,7 @@ test_files:
|
|
265
287
|
- spec/roqua/probes/delayed_job_probe_spec.rb
|
266
288
|
- spec/roqua/responders/active_interaction_aware_responder_spec.rb
|
267
289
|
- spec/roqua/responders/api_errors_responder_spec.rb
|
290
|
+
- spec/roqua/scheduling/scheduler_spec.rb
|
268
291
|
- spec/roqua/support/errors_spec.rb
|
269
292
|
- spec/roqua/support/helpers_spec.rb
|
270
293
|
- spec/roqua/support/logwrapper_spec.rb
|