crono 0.9.0 → 1.0.0.pre2
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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +2 -2
- data/Changes.md +5 -0
- data/Gemfile.lock +33 -30
- data/README.md +14 -6
- data/crono.gemspec +1 -0
- data/lib/crono.rb +2 -0
- data/lib/crono/cli.rb +62 -10
- data/lib/crono/config.rb +15 -2
- data/lib/crono/interval.rb +43 -0
- data/lib/crono/job.rb +32 -5
- data/lib/crono/performer_proxy.rb +12 -5
- data/lib/crono/period.rb +14 -3
- data/lib/crono/time_of_day.rb +36 -0
- data/lib/crono/version.rb +1 -1
- data/lib/generators/crono/install/templates/migrations/create_crono_jobs.rb +1 -0
- data/log/.keep +0 -0
- metadata +22 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ca8f0a63d98cd7d7906bfeeaa09e07b6bed50fb
|
4
|
+
data.tar.gz: 434e5621f3c326590477872019732b7764711066
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4cbb0f08ecbf361017d75838ba932a2f629fd58df6a7b00c7c0298a5a5e52e02d6e748df27153f2ec1237b6a61c7a061661b3c8b6097908b5afebbfdd2c8d0bc
|
7
|
+
data.tar.gz: a56a8a2686e5b298ffab856847869f6504f07bc6a3e3c849581e3b11819a2cd1a91327984f8422fd367ea75b82b111e7e488f1e378eee80b08a33972278156d9
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Changes.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,64 +1,63 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
crono (0.
|
4
|
+
crono (1.0.0.pre2)
|
5
5
|
activerecord (~> 4.0)
|
6
6
|
activesupport (~> 4.0)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
activemodel (4.2.
|
12
|
-
activesupport (= 4.2.
|
11
|
+
activemodel (4.2.5)
|
12
|
+
activesupport (= 4.2.5)
|
13
13
|
builder (~> 3.1)
|
14
|
-
activerecord (4.2.
|
15
|
-
activemodel (= 4.2.
|
16
|
-
activesupport (= 4.2.
|
14
|
+
activerecord (4.2.5)
|
15
|
+
activemodel (= 4.2.5)
|
16
|
+
activesupport (= 4.2.5)
|
17
17
|
arel (~> 6.0)
|
18
|
-
activesupport (4.2.
|
18
|
+
activesupport (4.2.5)
|
19
19
|
i18n (~> 0.7)
|
20
20
|
json (~> 1.7, >= 1.7.7)
|
21
21
|
minitest (~> 5.1)
|
22
22
|
thread_safe (~> 0.3, >= 0.3.4)
|
23
23
|
tzinfo (~> 1.1)
|
24
|
-
arel (6.0.
|
24
|
+
arel (6.0.3)
|
25
25
|
builder (3.2.2)
|
26
|
-
byebug (
|
27
|
-
|
28
|
-
columnize (0.9.0)
|
26
|
+
byebug (8.2.1)
|
27
|
+
daemons (1.2.3)
|
29
28
|
diff-lcs (1.2.5)
|
30
|
-
haml (4.0.
|
29
|
+
haml (4.0.7)
|
31
30
|
tilt
|
32
31
|
i18n (0.7.0)
|
33
|
-
json (1.8.
|
34
|
-
minitest (5.
|
35
|
-
rack (1.6.
|
32
|
+
json (1.8.3)
|
33
|
+
minitest (5.8.3)
|
34
|
+
rack (1.6.4)
|
36
35
|
rack-protection (1.5.3)
|
37
36
|
rack
|
38
37
|
rack-test (0.6.3)
|
39
38
|
rack (>= 1.0)
|
40
|
-
rake (10.
|
41
|
-
rspec (3.
|
42
|
-
rspec-core (~> 3.
|
43
|
-
rspec-expectations (~> 3.
|
44
|
-
rspec-mocks (~> 3.
|
45
|
-
rspec-core (3.
|
46
|
-
rspec-support (~> 3.
|
47
|
-
rspec-expectations (3.
|
39
|
+
rake (10.5.0)
|
40
|
+
rspec (3.4.0)
|
41
|
+
rspec-core (~> 3.4.0)
|
42
|
+
rspec-expectations (~> 3.4.0)
|
43
|
+
rspec-mocks (~> 3.4.0)
|
44
|
+
rspec-core (3.4.1)
|
45
|
+
rspec-support (~> 3.4.0)
|
46
|
+
rspec-expectations (3.4.0)
|
48
47
|
diff-lcs (>= 1.2.0, < 2.0)
|
49
|
-
rspec-support (~> 3.
|
50
|
-
rspec-mocks (3.
|
48
|
+
rspec-support (~> 3.4.0)
|
49
|
+
rspec-mocks (3.4.1)
|
51
50
|
diff-lcs (>= 1.2.0, < 2.0)
|
52
|
-
rspec-support (~> 3.
|
53
|
-
rspec-support (3.
|
51
|
+
rspec-support (~> 3.4.0)
|
52
|
+
rspec-support (3.4.1)
|
54
53
|
sinatra (1.4.6)
|
55
54
|
rack (~> 1.4)
|
56
55
|
rack-protection (~> 1.4)
|
57
56
|
tilt (>= 1.3, < 3)
|
58
|
-
sqlite3 (1.3.
|
57
|
+
sqlite3 (1.3.11)
|
59
58
|
thread_safe (0.3.5)
|
60
|
-
tilt (2.0.
|
61
|
-
timecop (0.
|
59
|
+
tilt (2.0.2)
|
60
|
+
timecop (0.8.0)
|
62
61
|
tzinfo (1.2.2)
|
63
62
|
thread_safe (~> 0.1)
|
64
63
|
|
@@ -69,6 +68,7 @@ DEPENDENCIES
|
|
69
68
|
bundler (>= 1.0.0)
|
70
69
|
byebug
|
71
70
|
crono!
|
71
|
+
daemons
|
72
72
|
haml
|
73
73
|
rack-test
|
74
74
|
rake (~> 10.0)
|
@@ -76,3 +76,6 @@ DEPENDENCIES
|
|
76
76
|
sinatra
|
77
77
|
sqlite3
|
78
78
|
timecop (~> 0.7)
|
79
|
+
|
80
|
+
BUNDLED WITH
|
81
|
+
1.11.2
|
data/README.md
CHANGED
@@ -61,11 +61,11 @@ class TestJob < ActiveJob::Base
|
|
61
61
|
end
|
62
62
|
```
|
63
63
|
|
64
|
-
The ActiveJob jobs is convenient because you can use one job in both periodic and enqueued ways. But Active Job is not required. Any class can be used as a crono job if it implements a method `perform
|
64
|
+
The ActiveJob jobs is convenient because you can use one job in both periodic and enqueued ways. But Active Job is not required. Any class can be used as a crono job if it implements a method `perform`:
|
65
65
|
|
66
66
|
```ruby
|
67
67
|
class TestJob # This is not an Active Job job, but pretty legal Crono job.
|
68
|
-
def perform
|
68
|
+
def perform(*args)
|
69
69
|
# put you scheduled code here
|
70
70
|
# Comments.deleted.clean_up...
|
71
71
|
end
|
@@ -124,6 +124,13 @@ The `at` can be a Hash:
|
|
124
124
|
Crono.perform(TestJob).every 1.day, at: {hour: 12, min: 15}
|
125
125
|
```
|
126
126
|
|
127
|
+
You can schedule a job with arguments, which can contain objects that can be
|
128
|
+
serialized using JSON.generate
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
Crono.perform(TestJob, 'some', 'args').every 1.day, at: {hour: 12, min: 15}
|
132
|
+
```
|
133
|
+
|
127
134
|
#### Run daemon
|
128
135
|
|
129
136
|
To run Crono daemon, in your Rails project root directory:
|
@@ -132,12 +139,13 @@ To run Crono daemon, in your Rails project root directory:
|
|
132
139
|
|
133
140
|
crono usage:
|
134
141
|
```
|
135
|
-
Usage: crono [options]
|
142
|
+
Usage: crono [options] start|stop|restart|run
|
136
143
|
-C, --cronotab PATH Path to cronotab file (Default: config/cronotab.rb)
|
137
144
|
-L, --logfile PATH Path to writable logfile (Default: log/crono.log)
|
138
|
-
|
139
|
-
-
|
140
|
-
-
|
145
|
+
--piddir PATH Path to piddir (Default: tmp/pids)
|
146
|
+
-N, --process_name name Name of the process (Default: crono)
|
147
|
+
-m, --monitor Start monitor process for a deamon (Default false)
|
148
|
+
-e, --environment ENV Application environment (Default: development)
|
141
149
|
```
|
142
150
|
|
143
151
|
|
data/crono.gemspec
CHANGED
data/lib/crono.rb
CHANGED
data/lib/crono/cli.rb
CHANGED
@@ -7,6 +7,8 @@ module Crono
|
|
7
7
|
include Singleton
|
8
8
|
include Logging
|
9
9
|
|
10
|
+
COMMANDS = %w(start stop restart run zap reload status)
|
11
|
+
|
10
12
|
attr_accessor :config
|
11
13
|
|
12
14
|
def initialize
|
@@ -16,16 +18,21 @@ module Crono
|
|
16
18
|
|
17
19
|
def run
|
18
20
|
parse_options(ARGV)
|
21
|
+
parse_command(ARGV)
|
19
22
|
|
20
|
-
setup_log
|
23
|
+
setup_log
|
21
24
|
|
22
|
-
write_pid
|
25
|
+
write_pid unless config.daemonize
|
23
26
|
load_rails
|
24
27
|
Cronotab.process(File.expand_path(config.cronotab))
|
25
28
|
print_banner
|
26
29
|
|
27
30
|
check_jobs
|
28
|
-
|
31
|
+
if config.daemonize
|
32
|
+
start_working_loop_in_daemon
|
33
|
+
else
|
34
|
+
start_working_loop
|
35
|
+
end
|
29
36
|
end
|
30
37
|
|
31
38
|
private
|
@@ -33,13 +40,15 @@ module Crono
|
|
33
40
|
def setup_log
|
34
41
|
if config.daemonize
|
35
42
|
self.logfile = config.logfile
|
36
|
-
|
43
|
+
elsif config.deprecated_daemonize
|
44
|
+
self.logfile = config.logfile
|
45
|
+
deprecated_daemonize
|
37
46
|
else
|
38
47
|
self.logfile = STDOUT
|
39
48
|
end
|
40
49
|
end
|
41
50
|
|
42
|
-
def
|
51
|
+
def deprecated_daemonize
|
43
52
|
::Process.daemon(true, true)
|
44
53
|
|
45
54
|
[$stdout, $stderr].each do |io|
|
@@ -79,6 +88,30 @@ module Crono
|
|
79
88
|
logger.error "You have no jobs in you cronotab file #{config.cronotab}"
|
80
89
|
end
|
81
90
|
|
91
|
+
def start_working_loop_in_daemon
|
92
|
+
unless ENV['RAILS_ENV'] == 'test'
|
93
|
+
begin
|
94
|
+
require 'daemons'
|
95
|
+
rescue LoadError
|
96
|
+
raise "You need to add gem 'daemons' to your Gemfile if you wish to use it."
|
97
|
+
end
|
98
|
+
end
|
99
|
+
Daemons.run_proc(config.process_name, dir: config.piddir, dir_mode: :normal, monitor: config.monitor, ARGV: @argv) do |*_argv|
|
100
|
+
Dir.chdir(root)
|
101
|
+
Crono.logger = Logger.new(config.logfile)
|
102
|
+
|
103
|
+
start_working_loop
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def root
|
108
|
+
@root ||= rails_root_defined? ? ::Rails.root : DIR_PWD
|
109
|
+
end
|
110
|
+
|
111
|
+
def rails_root_defined?
|
112
|
+
defined?(::Rails.root)
|
113
|
+
end
|
114
|
+
|
82
115
|
def start_working_loop
|
83
116
|
loop do
|
84
117
|
next_time, jobs = Crono.scheduler.next_jobs
|
@@ -88,8 +121,8 @@ module Crono
|
|
88
121
|
end
|
89
122
|
|
90
123
|
def parse_options(argv)
|
91
|
-
OptionParser.new do |opts|
|
92
|
-
opts.banner = "Usage: crono [options]"
|
124
|
+
@argv = OptionParser.new do |opts|
|
125
|
+
opts.banner = "Usage: crono [options] start|stop|restart|run"
|
93
126
|
|
94
127
|
opts.on("-C", "--cronotab PATH", "Path to cronotab file (Default: #{config.cronotab})") do |cronotab|
|
95
128
|
config.cronotab = cronotab
|
@@ -99,12 +132,24 @@ module Crono
|
|
99
132
|
config.logfile = logfile
|
100
133
|
end
|
101
134
|
|
102
|
-
opts.on("-P", "--pidfile PATH", "Path to pidfile (Default: #{config.pidfile})") do |pidfile|
|
135
|
+
opts.on("-P", "--pidfile PATH", "Deprecated! use --piddir with --process_name; Path to pidfile (Default: #{config.pidfile})") do |pidfile|
|
103
136
|
config.pidfile = pidfile
|
104
137
|
end
|
105
138
|
|
106
|
-
opts.on("
|
107
|
-
config.
|
139
|
+
opts.on("--piddir PATH", "Path to piddir (Default: #{config.piddir})") do |piddir|
|
140
|
+
config.piddir = piddir
|
141
|
+
end
|
142
|
+
|
143
|
+
opts.on("-N", "--process_name NAME", "Name of the process (Default: #{config.process_name})") do |process_name|
|
144
|
+
config.process_name = process_name
|
145
|
+
end
|
146
|
+
|
147
|
+
opts.on("-d", "--[no-]daemonize", "Deprecated! Instead use crono [start|stop|restart] without this option; Daemonize process (Default: #{config.daemonize})") do |daemonize|
|
148
|
+
config.deprecated_daemonize = daemonize
|
149
|
+
end
|
150
|
+
|
151
|
+
opts.on("-m", "--monitor", "Start monitor process for a deamon (Default #{config.monitor})") do
|
152
|
+
config.monitor = true
|
108
153
|
end
|
109
154
|
|
110
155
|
opts.on '-e', '--environment ENV', "Application environment (Default: #{config.environment})" do |env|
|
@@ -112,5 +157,12 @@ module Crono
|
|
112
157
|
end
|
113
158
|
end.parse!(argv)
|
114
159
|
end
|
160
|
+
|
161
|
+
def parse_command(argv)
|
162
|
+
if COMMANDS.include? argv[0]
|
163
|
+
config.daemonize = true
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
115
167
|
end
|
116
168
|
end
|
data/lib/crono/config.rb
CHANGED
@@ -4,18 +4,31 @@ module Crono
|
|
4
4
|
CRONOTAB = 'config/cronotab.rb'
|
5
5
|
LOGFILE = 'log/crono.log'
|
6
6
|
PIDFILE = 'tmp/pids/crono.pid'
|
7
|
+
PIDDIR = 'tmp/pids'
|
8
|
+
PROCESS_NAME = 'crono'
|
7
9
|
|
8
|
-
attr_accessor :cronotab, :logfile, :pidfile, :
|
10
|
+
attr_accessor :cronotab, :logfile, :pidfile, :piddir, :process_name,
|
11
|
+
:monitor, :daemonize, :deprecated_daemonize, :environment
|
9
12
|
|
10
13
|
def initialize
|
11
14
|
self.cronotab = CRONOTAB
|
12
15
|
self.logfile = LOGFILE
|
16
|
+
self.piddir = PIDDIR
|
17
|
+
self.process_name = PROCESS_NAME
|
13
18
|
self.daemonize = false
|
19
|
+
self.deprecated_daemonize = false
|
20
|
+
self.monitor = false
|
14
21
|
self.environment = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
15
22
|
end
|
16
23
|
|
24
|
+
def pidfile=(pidfile)
|
25
|
+
@pidfile = pidfile
|
26
|
+
self.process_name = Pathname.new(pidfile).basename(".*").to_s
|
27
|
+
self.piddir = Pathname.new(pidfile).dirname.to_s
|
28
|
+
end
|
29
|
+
|
17
30
|
def pidfile
|
18
|
-
@pidfile || (
|
31
|
+
@pidfile || (deprecated_daemonize ? PIDFILE : nil)
|
19
32
|
end
|
20
33
|
end
|
21
34
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Crono
|
2
|
+
# Interval describes a period between two specific times of day
|
3
|
+
class Interval
|
4
|
+
attr_accessor :from, :to
|
5
|
+
|
6
|
+
def self.parse(value)
|
7
|
+
from_to =
|
8
|
+
case value
|
9
|
+
when Array then value
|
10
|
+
when Hash then value.values_at(:from, :to)
|
11
|
+
when String then value.split('-')
|
12
|
+
else
|
13
|
+
fail "Unknown interval format: #{value.inspect}"
|
14
|
+
end
|
15
|
+
from, to = from_to.map { |v| TimeOfDay.parse(v) }
|
16
|
+
new from, to
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(from, to)
|
20
|
+
@from, @to = from, to
|
21
|
+
end
|
22
|
+
|
23
|
+
def within?(value)
|
24
|
+
tod = ((value.is_a? TimeOfDay) ? value : TimeOfDay.parse(value))
|
25
|
+
if @from <= @to
|
26
|
+
tod >= @from && tod < @to
|
27
|
+
else
|
28
|
+
tod >= @from || tod < @to
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def next_within(time, period)
|
33
|
+
begin
|
34
|
+
time = period.since(time)
|
35
|
+
end until within? TimeOfDay.parse(time)
|
36
|
+
time
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
"#{@from}-#{@to}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/crono/job.rb
CHANGED
@@ -6,11 +6,13 @@ module Crono
|
|
6
6
|
class Job
|
7
7
|
include Logging
|
8
8
|
|
9
|
-
attr_accessor :performer, :period, :last_performed_at,
|
10
|
-
:next_performed_at, :job_log, :job_logger, :healthy
|
9
|
+
attr_accessor :performer, :period, :job_args, :last_performed_at,
|
10
|
+
:next_performed_at, :job_log, :job_logger, :healthy, :execution_interval
|
11
11
|
|
12
|
-
def initialize(performer, period)
|
12
|
+
def initialize(performer, period, job_args)
|
13
|
+
self.execution_interval = 0.minutes
|
13
14
|
self.performer, self.period = performer, period
|
15
|
+
self.job_args = JSON.generate(job_args)
|
14
16
|
self.job_log = StringIO.new
|
15
17
|
self.job_logger = Logger.new(job_log)
|
16
18
|
self.next_performed_at = period.next
|
@@ -31,6 +33,8 @@ module Crono
|
|
31
33
|
end
|
32
34
|
|
33
35
|
def perform
|
36
|
+
return Thread.new {} if perform_before_interval?
|
37
|
+
|
34
38
|
log "Perform #{performer}"
|
35
39
|
self.last_performed_at = Time.now
|
36
40
|
self.next_performed_at = period.next(since: last_performed_at)
|
@@ -42,6 +46,7 @@ module Crono
|
|
42
46
|
@semaphore.synchronize do
|
43
47
|
update_model
|
44
48
|
clear_job_log
|
49
|
+
ActiveRecord::Base.clear_active_connections!
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
@@ -60,11 +65,11 @@ module Crono
|
|
60
65
|
saved_log = model.reload.log || ''
|
61
66
|
log_to_save = saved_log + job_log.string
|
62
67
|
model.update(last_performed_at: last_performed_at, log: log_to_save,
|
63
|
-
healthy: healthy)
|
68
|
+
healthy: healthy, args: job_args)
|
64
69
|
end
|
65
70
|
|
66
71
|
def perform_job
|
67
|
-
performer.new.perform
|
72
|
+
performer.new.perform *JSON.parse(job_args)
|
68
73
|
rescue StandardError => e
|
69
74
|
handle_job_fail(e)
|
70
75
|
else
|
@@ -101,5 +106,27 @@ module Crono
|
|
101
106
|
def model
|
102
107
|
@model ||= Crono::CronoJob.find_or_create_by(job_id: job_id)
|
103
108
|
end
|
109
|
+
|
110
|
+
def perform_before_interval?
|
111
|
+
return false if execution_interval == 0.minutes
|
112
|
+
|
113
|
+
return true if self.last_performed_at.present? && self.last_performed_at > execution_interval.ago
|
114
|
+
return true if model.updated_at.present? && model.created_at != model.updated_at && model.updated_at > execution_interval.ago
|
115
|
+
|
116
|
+
Crono::CronoJob.transaction do
|
117
|
+
job_record = Crono::CronoJob.where(job_id: job_id).lock(true).first
|
118
|
+
|
119
|
+
return true if job_record.updated_at.present? &&
|
120
|
+
job_record.updated_at != job_record.created_at &&
|
121
|
+
job_record.updated_at > execution_interval.ago
|
122
|
+
|
123
|
+
job_record.touch
|
124
|
+
|
125
|
+
return true unless job_record.save
|
126
|
+
end
|
127
|
+
|
128
|
+
# Means that this node is permit to perform the job.
|
129
|
+
return false
|
130
|
+
end
|
104
131
|
end
|
105
132
|
end
|
@@ -1,18 +1,25 @@
|
|
1
1
|
module Crono
|
2
2
|
# Crono::PerformerProxy is a proxy used in cronotab.rb semantic
|
3
3
|
class PerformerProxy
|
4
|
-
def initialize(performer, scheduler)
|
4
|
+
def initialize(performer, scheduler, job_args)
|
5
5
|
@performer = performer
|
6
6
|
@scheduler = scheduler
|
7
|
+
@job_args = job_args
|
7
8
|
end
|
8
9
|
|
9
10
|
def every(period, *args)
|
10
|
-
job = Job.new(@performer, Period.new(period, *args))
|
11
|
-
@scheduler.add_job(job)
|
11
|
+
@job = Job.new(@performer, Period.new(period, *args), @job_args)
|
12
|
+
@scheduler.add_job(@job)
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def once_per(execution_interval)
|
17
|
+
@job.execution_interval = execution_interval if @job
|
18
|
+
self
|
12
19
|
end
|
13
20
|
end
|
14
21
|
|
15
|
-
def self.perform(performer)
|
16
|
-
PerformerProxy.new(performer, Crono.scheduler)
|
22
|
+
def self.perform(performer, *job_args)
|
23
|
+
PerformerProxy.new(performer, Crono.scheduler, job_args)
|
17
24
|
end
|
18
25
|
end
|
data/lib/crono/period.rb
CHANGED
@@ -4,15 +4,25 @@ module Crono
|
|
4
4
|
DAYS = [:monday, :tuesday, :wednesday, :thursday, :friday, :saturday,
|
5
5
|
:sunday]
|
6
6
|
|
7
|
-
def initialize(period, at: nil, on: nil)
|
7
|
+
def initialize(period, at: nil, on: nil, within: nil)
|
8
8
|
@period = period
|
9
9
|
@at_hour, @at_min = parse_at(at) if at
|
10
|
+
@interval = Interval.parse(within) if within
|
10
11
|
@on = parse_on(on) if on
|
11
12
|
end
|
12
13
|
|
13
14
|
def next(since: nil)
|
14
|
-
|
15
|
-
|
15
|
+
if @interval
|
16
|
+
if since
|
17
|
+
@next = @interval.next_within(since, @period)
|
18
|
+
else
|
19
|
+
return initial_next if @interval.within?(initial_next)
|
20
|
+
@next = @interval.next_within(initial_next, @period)
|
21
|
+
end
|
22
|
+
else
|
23
|
+
return initial_next unless since
|
24
|
+
@next = @period.since(since)
|
25
|
+
end
|
16
26
|
@next = @next.beginning_of_week.advance(days: @on) if @on
|
17
27
|
@next = @next.change(time_atts)
|
18
28
|
return @next if @next.future?
|
@@ -21,6 +31,7 @@ module Crono
|
|
21
31
|
|
22
32
|
def description
|
23
33
|
desc = "every #{@period.inspect}"
|
34
|
+
desc += " between #{@interval.from} and #{@interval.to} UTC" if @interval
|
24
35
|
desc += format(' at %.2i:%.2i', @at_hour, @at_min) if @at_hour && @at_min
|
25
36
|
desc += " on #{DAYS[@on].capitalize}" if @on
|
26
37
|
desc
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Crono
|
2
|
+
# TimeOfDay describes a certain hour and minute (on any day)
|
3
|
+
class TimeOfDay
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
attr_accessor :hour, :min
|
7
|
+
|
8
|
+
def self.parse(value)
|
9
|
+
time =
|
10
|
+
case value
|
11
|
+
when String then Time.parse(value).utc
|
12
|
+
when Hash then Time.now.change(value).utc
|
13
|
+
when Time then value.utc
|
14
|
+
else
|
15
|
+
fail "Unknown TimeOfDay format: #{value.inspect}"
|
16
|
+
end
|
17
|
+
new time.hour, time.min
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(hour, min)
|
21
|
+
@hour, @min = hour, min
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_i
|
25
|
+
@hour * 60 + @min
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
'%02d:%02d' % [@hour, @min]
|
30
|
+
end
|
31
|
+
|
32
|
+
def <=>(other)
|
33
|
+
to_i <=> other.to_i
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/crono/version.rb
CHANGED
data/log/.keep
ADDED
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crono
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.pre2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dzmitry Plashchynski
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -164,6 +164,20 @@ dependencies:
|
|
164
164
|
- - ">="
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: daemons
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
167
181
|
description: A time-based background job scheduler daemon (just like Cron) for Rails
|
168
182
|
email:
|
169
183
|
- plashchynski@gmail.com
|
@@ -193,6 +207,7 @@ files:
|
|
193
207
|
- lib/crono/cli.rb
|
194
208
|
- lib/crono/config.rb
|
195
209
|
- lib/crono/cronotab.rb
|
210
|
+
- lib/crono/interval.rb
|
196
211
|
- lib/crono/job.rb
|
197
212
|
- lib/crono/logging.rb
|
198
213
|
- lib/crono/orm/active_record/crono_job.rb
|
@@ -200,12 +215,14 @@ files:
|
|
200
215
|
- lib/crono/period.rb
|
201
216
|
- lib/crono/railtie.rb
|
202
217
|
- lib/crono/scheduler.rb
|
218
|
+
- lib/crono/time_of_day.rb
|
203
219
|
- lib/crono/version.rb
|
204
220
|
- lib/crono/web.rb
|
205
221
|
- lib/generators/crono/install/install_generator.rb
|
206
222
|
- lib/generators/crono/install/templates/cronotab.rb.erb
|
207
223
|
- lib/generators/crono/install/templates/migrations/create_crono_jobs.rb
|
208
224
|
- lib/tasks/crono_tasks.rake
|
225
|
+
- log/.keep
|
209
226
|
- tmp/.gitkeep
|
210
227
|
- web/assets/css/custom.css
|
211
228
|
- web/assets/css/materialize.min.css
|
@@ -250,12 +267,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
250
267
|
version: '0'
|
251
268
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
252
269
|
requirements:
|
253
|
-
- - "
|
270
|
+
- - ">"
|
254
271
|
- !ruby/object:Gem::Version
|
255
|
-
version:
|
272
|
+
version: 1.3.1
|
256
273
|
requirements: []
|
257
274
|
rubyforge_project:
|
258
|
-
rubygems_version: 2.
|
275
|
+
rubygems_version: 2.5.1
|
259
276
|
signing_key:
|
260
277
|
specification_version: 4
|
261
278
|
summary: Job scheduler for Rails
|