perfectsched 0.8.4 → 0.8.5
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.
- data/ChangeLog +8 -0
- data/lib/perfectsched/application/decider.rb +1 -1
- data/lib/perfectsched/application/dispatch.rb +3 -3
- data/lib/perfectsched/backend/rdb_compat.rb +44 -24
- data/lib/perfectsched/client.rb +2 -3
- data/lib/perfectsched/command/perfectsched.rb +6 -6
- data/lib/perfectsched/schedule_collection.rb +2 -2
- data/lib/perfectsched/schedule_metadata.rb +1 -8
- data/lib/perfectsched/version.rb +1 -1
- data/lib/perfectsched/worker.rb +9 -9
- data/spec/rdb_compat_backend_spec.rb +0 -2
- data/spec/schedule_collection_spec.rb +63 -25
- data/spec/worker_spec.rb +2 -2
- metadata +62 -19
data/ChangeLog
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
|
2
|
+
== 2012-12-12 version 0.8.5
|
3
|
+
|
4
|
+
* show version when worker starts
|
5
|
+
* rdb_compat backend supports :only_keys option at acquire
|
6
|
+
* rdb_compat backend supports :update_data option at finish
|
7
|
+
* fixed ScheduleMetadata#initialize
|
8
|
+
|
9
|
+
|
2
10
|
== 2012-07-06 version 0.8.4
|
3
11
|
|
4
12
|
* Introduced PerfectSched::Application::Decider
|
@@ -40,7 +40,7 @@ module PerfectSched
|
|
40
40
|
begin
|
41
41
|
m = method(type)
|
42
42
|
rescue NameError
|
43
|
-
raise UndefinedDecisionError, "Undefined decision #{type} options=#{
|
43
|
+
raise UndefinedDecisionError, "Undefined decision #{type} options=#{opts.inspect}"
|
44
44
|
end
|
45
45
|
m.call(opts)
|
46
46
|
end
|
@@ -22,10 +22,10 @@ module PerfectSched
|
|
22
22
|
class Dispatch < Runner
|
23
23
|
# Runner interface
|
24
24
|
def initialize(task)
|
25
|
-
base = self.class.router.route(task.
|
25
|
+
base = self.class.router.route(task.key)
|
26
26
|
unless base
|
27
|
-
task.retry!
|
28
|
-
raise "Unknown task
|
27
|
+
task.retry! # TODO or release?
|
28
|
+
raise "Unknown task key #{task.key.inspect}" # TODO error class
|
29
29
|
end
|
30
30
|
@runner = base.new(task)
|
31
31
|
super
|
@@ -21,7 +21,7 @@ module PerfectSched
|
|
21
21
|
class RDBCompatBackend
|
22
22
|
include BackendHelper
|
23
23
|
|
24
|
-
class Token < Struct.new(:row_id, :scheduled_time, :cron, :delay, :timezone)
|
24
|
+
class Token < Struct.new(:row_id, :scheduled_time, :cron, :delay, :timezone, :data)
|
25
25
|
end
|
26
26
|
|
27
27
|
def initialize(client, config)
|
@@ -60,8 +60,8 @@ module PerfectSched
|
|
60
60
|
next_time INT NOT NULL,
|
61
61
|
cron VARCHAR(128) NOT NULL,
|
62
62
|
delay INT NOT NULL,
|
63
|
-
data BLOB NOT NULL,
|
64
63
|
timezone VARCHAR(256) NULL,
|
64
|
+
data BLOB NOT NULL,
|
65
65
|
PRIMARY KEY (id)
|
66
66
|
);]
|
67
67
|
connect {
|
@@ -71,7 +71,7 @@ module PerfectSched
|
|
71
71
|
|
72
72
|
def get_schedule_metadata(key, options={})
|
73
73
|
connect {
|
74
|
-
row = @db.fetch("SELECT id, timeout, next_time, cron, delay,
|
74
|
+
row = @db.fetch("SELECT id, timeout, next_time, cron, delay, timezone, data FROM `#{@table}` WHERE id=? LIMIT 1", key).first
|
75
75
|
unless row
|
76
76
|
raise NotFoundError, "schedule key=#{key} does not exist"
|
77
77
|
end
|
@@ -82,7 +82,7 @@ module PerfectSched
|
|
82
82
|
|
83
83
|
def list(options, &block)
|
84
84
|
connect {
|
85
|
-
@db.fetch("SELECT id, timeout, next_time, cron, delay,
|
85
|
+
@db.fetch("SELECT id, timeout, next_time, cron, delay, timezone, data FROM `#{@table}` ORDER BY timeout ASC") {|row|
|
86
86
|
attributes = create_attributes(row)
|
87
87
|
sched = ScheduleWithMetadata.new(@client, row[:id], attributes)
|
88
88
|
yield sched
|
@@ -90,12 +90,11 @@ module PerfectSched
|
|
90
90
|
}
|
91
91
|
end
|
92
92
|
|
93
|
-
def add(key,
|
94
|
-
data = data
|
95
|
-
data['type'] = type
|
93
|
+
def add(key, cron, delay, timezone, next_time, next_run_time, options)
|
94
|
+
data = options[:data] || {}
|
96
95
|
connect {
|
97
96
|
begin
|
98
|
-
n = @db["INSERT INTO `#{@table}` (id, timeout, next_time, cron, delay,
|
97
|
+
n = @db["INSERT INTO `#{@table}` (id, timeout, next_time, cron, delay, timezone, data) VALUES (?, ?, ?, ?, ?, ?, ?)", key, next_run_time, next_time, cron, delay, timezone, data.to_json].insert
|
99
98
|
return Schedule.new(@client, key)
|
100
99
|
rescue Sequel::DatabaseError
|
101
100
|
raise IdempotentAlreadyExistsError, "schedule key=#{key} already exists"
|
@@ -105,7 +104,7 @@ module PerfectSched
|
|
105
104
|
|
106
105
|
def delete(key, options)
|
107
106
|
connect {
|
108
|
-
n = @db["DELETE FROM `#{@table}` WHERE id
|
107
|
+
n = @db["DELETE FROM `#{@table}` WHERE id=?", key].delete
|
109
108
|
if n <= 0
|
110
109
|
raise IdempotentNotFoundError, "schedule key=#{key} does no exist"
|
111
110
|
end
|
@@ -116,12 +115,17 @@ module PerfectSched
|
|
116
115
|
ks = []
|
117
116
|
vs = []
|
118
117
|
[:cron, :delay, :timezone].each {|k|
|
119
|
-
# TODO type and data are not supported
|
120
118
|
if v = options[k]
|
121
119
|
ks << k
|
122
120
|
vs << v
|
123
121
|
end
|
124
122
|
}
|
123
|
+
[:data].each {|k|
|
124
|
+
if v = options[k]
|
125
|
+
ks << k
|
126
|
+
vs << v.to_json
|
127
|
+
end
|
128
|
+
}
|
125
129
|
return nil if ks.empty?
|
126
130
|
|
127
131
|
sql = "UPDATE `#{@table}` SET "
|
@@ -142,17 +146,29 @@ module PerfectSched
|
|
142
146
|
def acquire(alive_time, max_acquire, options)
|
143
147
|
now = (options[:now] || Time.now).to_i
|
144
148
|
next_timeout = now + alive_time
|
149
|
+
only_keys = options[:only_keys]
|
150
|
+
|
151
|
+
select_sql = "SELECT id, timeout, next_time, cron, delay, timezone, data FROM `#{@table}` WHERE timeout <= ?"
|
152
|
+
select_params = [select_sql, now]
|
153
|
+
if only_keys
|
154
|
+
select_sql << " AND id IN ("
|
155
|
+
select_sql << only_keys.map {|k|
|
156
|
+
select_params << k
|
157
|
+
'?'
|
158
|
+
}.join(', ')
|
159
|
+
select_sql << ')'
|
160
|
+
end
|
161
|
+
select_sql << " ORDER BY timeout ASC LIMIT #{MAX_SELECT_ROW}"
|
145
162
|
|
146
163
|
connect {
|
147
164
|
while true
|
148
165
|
rows = 0
|
149
|
-
@db.fetch(
|
150
|
-
|
151
|
-
n = @db["UPDATE `#{@table}` SET timeout=? WHERE id=? AND timeout=?;", next_timeout, row[:id], row[:timeout]].update
|
166
|
+
@db.fetch(*select_params) {|row|
|
167
|
+
n = @db["UPDATE `#{@table}` SET timeout=? WHERE id=? AND timeout=?", next_timeout, row[:id], row[:timeout]].update
|
152
168
|
if n > 0
|
153
169
|
scheduled_time = row[:next_time]
|
154
170
|
attributes = create_attributes(row)
|
155
|
-
task_token = Token.new(row[:id], row[:next_time], attributes[:cron], attributes[:delay], attributes[:timezone])
|
171
|
+
task_token = Token.new(row[:id], row[:next_time], attributes[:cron], attributes[:delay], attributes[:timezone], attributes[:data].dup)
|
156
172
|
task = Task.new(@client, row[:id], attributes, scheduled_time, task_token)
|
157
173
|
return [task]
|
158
174
|
end
|
@@ -173,7 +189,7 @@ module PerfectSched
|
|
173
189
|
next_run_time = now + alive_time
|
174
190
|
|
175
191
|
connect {
|
176
|
-
n = @db["UPDATE `#{@table}` SET timeout=? WHERE id=? AND next_time
|
192
|
+
n = @db["UPDATE `#{@table}` SET timeout=? WHERE id=? AND next_time=?", next_run_time, row_id, scheduled_time].update
|
177
193
|
if n <= 0 # TODO fix
|
178
194
|
row = @db.fetch("SELECT id, timeout, next_time FROM `#{@table}` WHERE id=? AND next_time=? LIMIT 1", row_id, scheduled_time).first
|
179
195
|
if row == nil
|
@@ -192,9 +208,20 @@ module PerfectSched
|
|
192
208
|
scheduled_time = task_token.scheduled_time
|
193
209
|
next_time = PerfectSched.next_time(task_token.cron, scheduled_time, task_token.timezone)
|
194
210
|
next_run_time = next_time + task_token.delay
|
211
|
+
update_data = options[:update_data]
|
212
|
+
|
213
|
+
update_sql = "UPDATE `#{@table}` SET timeout=?, next_time=?"
|
214
|
+
update_params = [update_sql, next_run_time, next_time]
|
215
|
+
if update_data
|
216
|
+
new_data = task_token.data.merge(update_data)
|
217
|
+
update_sql << ", data=?"
|
218
|
+
update_params << new_data.to_json
|
219
|
+
end
|
220
|
+
update_sql << " WHERE id=? AND next_time=?"
|
221
|
+
update_params << row_id << scheduled_time
|
195
222
|
|
196
223
|
connect {
|
197
|
-
n = @db[
|
224
|
+
n = @db[*update_params].update
|
198
225
|
if n <= 0
|
199
226
|
raise IdempotentAlreadyFinishedError, "task time=#{Time.at(scheduled_time).utc} is already finished"
|
200
227
|
end
|
@@ -245,11 +272,6 @@ module PerfectSched
|
|
245
272
|
end
|
246
273
|
end
|
247
274
|
|
248
|
-
type = data.delete('type')
|
249
|
-
if type == nil || type.empty?
|
250
|
-
type = row[:id].split(/\./, 2)[0]
|
251
|
-
end
|
252
|
-
|
253
275
|
attributes = {
|
254
276
|
:timezone => timezone,
|
255
277
|
:delay => delay,
|
@@ -257,9 +279,7 @@ module PerfectSched
|
|
257
279
|
:data => data,
|
258
280
|
:next_time => next_time,
|
259
281
|
:next_run_time => next_run_time,
|
260
|
-
|
261
|
-
:message => nil, # not supported
|
262
|
-
:node => nil, # not supported
|
282
|
+
#:node => nil, # not supported
|
263
283
|
}
|
264
284
|
end
|
265
285
|
|
data/lib/perfectsched/client.rb
CHANGED
@@ -47,14 +47,13 @@ module PerfectSched
|
|
47
47
|
# :data
|
48
48
|
# :delay => 0
|
49
49
|
# :timezone => UTC
|
50
|
-
def add(key,
|
50
|
+
def add(key, options={})
|
51
51
|
cron = options[:cron]
|
52
52
|
|
53
53
|
raise ArgumentError, ":cron option is required" unless cron
|
54
54
|
|
55
55
|
delay = options[:delay] || 0
|
56
56
|
timezone = options[:timezone] || @timezone
|
57
|
-
data = options[:data] || {}
|
58
57
|
|
59
58
|
next_time = options[:next_time] || Time.now.to_i
|
60
59
|
next_time = PerfectSched.cron_time(cron, next_time.to_i, timezone)
|
@@ -66,7 +65,7 @@ module PerfectSched
|
|
66
65
|
next_run_time = next_time + delay
|
67
66
|
end
|
68
67
|
|
69
|
-
@backend.add(key,
|
68
|
+
@backend.add(key, cron, delay, timezone, next_time, next_run_time, options)
|
70
69
|
|
71
70
|
# TODO return value
|
72
71
|
return next_time, next_run_time
|
@@ -7,7 +7,7 @@ op.banner += %[ <command>
|
|
7
7
|
|
8
8
|
commands:
|
9
9
|
list Show list of registered schedules
|
10
|
-
add <key> <
|
10
|
+
add <key> <cron> <data> Register a new schedule
|
11
11
|
delete <key> Delete a registered schedule
|
12
12
|
run <class> Run a worker process
|
13
13
|
init Initialize a backend database
|
@@ -91,8 +91,8 @@ begin
|
|
91
91
|
|
92
92
|
when 'add'
|
93
93
|
cmd = :add
|
94
|
-
usage nil unless ARGV.length ==
|
95
|
-
key,
|
94
|
+
usage nil unless ARGV.length == 3
|
95
|
+
key, cron, data = *ARGV
|
96
96
|
require 'json'
|
97
97
|
data = JSON.load(data)
|
98
98
|
|
@@ -130,11 +130,11 @@ when :list
|
|
130
130
|
n = 0
|
131
131
|
PerfectSched.open(config_load_proc.call) {|scheds|
|
132
132
|
format = "%30s %15s %18s %7s %11s %28s %28s %s"
|
133
|
-
puts format % ['key', '
|
133
|
+
puts format % ['key', 'cron', 'delay', 'timezone', 'next_time', 'next_run_time', 'data']
|
134
134
|
scheds.list {|sched|
|
135
135
|
next_time = sched.next_time ? Time.at(sched.next_time) : sched.next_time
|
136
136
|
next_run_time = sched.next_run_time ? Time.at(sched.next_run_time) : sched.next_run_time
|
137
|
-
puts format % [sched.key, sched.
|
137
|
+
puts format % [sched.key, sched.cron, sched.delay, sched.timezone, next_time, next_run_time, sched.data]
|
138
138
|
n += 1
|
139
139
|
}
|
140
140
|
}
|
@@ -149,7 +149,7 @@ when :add
|
|
149
149
|
PerfectSched.open(config_load_proc.call) {|scheds|
|
150
150
|
add_options[:cron] = cron
|
151
151
|
add_options[:data] = data
|
152
|
-
scheds.add(key,
|
152
|
+
scheds.add(key, add_options)
|
153
153
|
}
|
154
154
|
|
155
155
|
when :run
|
@@ -21,10 +21,6 @@ module PerfectSched
|
|
21
21
|
module ScheduleMetadataAccessors
|
22
22
|
attr_reader :attributes
|
23
23
|
|
24
|
-
def type
|
25
|
-
@attributes[:type]
|
26
|
-
end
|
27
|
-
|
28
24
|
def data
|
29
25
|
@attributes[:data]
|
30
26
|
end
|
@@ -52,10 +48,6 @@ module PerfectSched
|
|
52
48
|
alias scheduled_time next_time
|
53
49
|
|
54
50
|
alias scheduled_run_time next_run_time
|
55
|
-
|
56
|
-
def message
|
57
|
-
@attributes[:message]
|
58
|
-
end
|
59
51
|
end
|
60
52
|
|
61
53
|
class ScheduleMetadata
|
@@ -64,6 +56,7 @@ module PerfectSched
|
|
64
56
|
def initialize(client, key, attributes)
|
65
57
|
super(client)
|
66
58
|
@key = key
|
59
|
+
@attributes = attributes
|
67
60
|
end
|
68
61
|
|
69
62
|
def schedule
|
data/lib/perfectsched/version.rb
CHANGED
data/lib/perfectsched/worker.rb
CHANGED
@@ -35,19 +35,19 @@ module PerfectSched
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def run
|
38
|
-
@
|
38
|
+
@log.info "PerfectSched #{VERSION}"
|
39
|
+
|
40
|
+
install_signal_handlers
|
41
|
+
|
42
|
+
@engine = Engine.new(@runner, load_config)
|
39
43
|
begin
|
40
|
-
|
41
|
-
|
42
|
-
until @finished
|
43
|
-
@engine.run
|
44
|
-
end
|
45
|
-
ensure
|
46
|
-
@engine.shutdown
|
44
|
+
until @finished
|
45
|
+
@engine.run
|
47
46
|
end
|
48
47
|
ensure
|
49
|
-
@
|
48
|
+
@engine.shutdown
|
50
49
|
end
|
50
|
+
|
51
51
|
return nil
|
52
52
|
rescue
|
53
53
|
@log.error "#{$!.class}: #{$!}"
|
@@ -23,7 +23,6 @@ describe Backend::RDBCompatBackend do
|
|
23
23
|
ts.should_not == nil
|
24
24
|
t = ts[0]
|
25
25
|
t.data.should == {'account_id'=>1}
|
26
|
-
t.type.should == 'maint_sched'
|
27
26
|
t.key.should == 'maint_sched.1.do_hourly'
|
28
27
|
t.next_time.should == 1339812000
|
29
28
|
end
|
@@ -33,7 +32,6 @@ describe Backend::RDBCompatBackend do
|
|
33
32
|
ts = backend.acquire(60, 1, {:now=>1339812060})
|
34
33
|
t = ts[0]
|
35
34
|
t.data.should == {}
|
36
|
-
t.type.should == 'merge'
|
37
35
|
t.key.should == 'merge'
|
38
36
|
t.next_time.should == 1339812000
|
39
37
|
end
|
@@ -13,29 +13,28 @@ describe ScheduleCollection do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'succeess add' do
|
16
|
-
sc.add('sched01',
|
16
|
+
sc.add('sched01', {:cron=>'* * * * *', :timezone=>'UTC'})
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'fail duplicated add' do
|
20
|
-
sc.add('sched01',
|
20
|
+
sc.add('sched01', {:cron=>'* * * * *', :timezone=>'UTC'})
|
21
21
|
|
22
22
|
lambda {
|
23
|
-
sc.add('sched01',
|
23
|
+
sc.add('sched01', {:cron=>'* * * * *', :timezone=>'UTC'})
|
24
24
|
}.should raise_error AlreadyExistsError
|
25
25
|
|
26
26
|
sc['sched01'].delete!
|
27
27
|
|
28
|
-
sc.add('sched01',
|
28
|
+
sc.add('sched01', {:cron=>'* * * * *', :timezone=>'UTC'})
|
29
29
|
end
|
30
30
|
|
31
31
|
it 'acquire' do
|
32
32
|
time = 1323820800 # 2011-12-14 00:00:00 UTC
|
33
33
|
|
34
|
-
s01 = sc.add('sched01',
|
34
|
+
s01 = sc.add('sched01', :cron=>"* * * * *", :data=>{'k'=>1}, :next_time=>time)
|
35
35
|
|
36
36
|
t01 = sc.poll(:alive_time=>120, :now=>time)
|
37
37
|
t01.key.should == 'sched01'
|
38
|
-
t01.type.should == 't01'
|
39
38
|
t01.cron.should == "* * * * *"
|
40
39
|
t01.delay.should == 0
|
41
40
|
t01.data.should == {'k'=>1}
|
@@ -48,7 +47,6 @@ describe ScheduleCollection do
|
|
48
47
|
|
49
48
|
t04 = sc.poll(:alive_time=>120, :now=>time+60)
|
50
49
|
t04.key.should == 'sched01'
|
51
|
-
t01.type.should == 't01'
|
52
50
|
t04.cron.should == "* * * * *"
|
53
51
|
t04.delay.should == 0
|
54
52
|
t04.data.should == {'k'=>1}
|
@@ -58,31 +56,29 @@ describe ScheduleCollection do
|
|
58
56
|
it 'timezone' do
|
59
57
|
time = 1323820800 # 2011-12-14 00:00:00 UTC
|
60
58
|
|
61
|
-
s01 = sc.add('sched01',
|
59
|
+
s01 = sc.add('sched01', :cron=>"0 0 * * *", :next_time=>time-60, :timezone=>'UTC')
|
62
60
|
#s01.class.should == Schedule
|
63
61
|
#s01.key.should == 'sched01'
|
64
62
|
|
65
|
-
s02 = sc.add('sched02',
|
63
|
+
s02 = sc.add('sched02', :cron=>"0 0 * * *", :next_time=>time-60, :timezone=>'Asia/Tokyo')
|
66
64
|
#s02.class.should == Schedule
|
67
65
|
#s02.key.should == 'sched02'
|
68
66
|
|
69
67
|
t01 = sc.poll(:alive_time=>86400, :now=>time)
|
70
68
|
t01.class.should == Task
|
71
69
|
t01.key.should == 'sched01'
|
72
|
-
t01.type.should == 't01'
|
73
70
|
t01.scheduled_time.should == time
|
74
71
|
|
75
72
|
t02 = sc.poll(:alive_time=>86400, :now=>time+54000)
|
76
73
|
t02.class.should == Task
|
77
74
|
t02.key.should == 'sched02'
|
78
|
-
t02.type.should == 't01'
|
79
75
|
t02.scheduled_time.should == time+54000
|
80
76
|
end
|
81
77
|
|
82
78
|
it 'delay' do
|
83
79
|
time = 1323820800 # 2011-12-14 00:00:00 UTC
|
84
80
|
|
85
|
-
s01 = sc.add('sched01',
|
81
|
+
s01 = sc.add('sched01', :cron=>"0 * * * *", :delay=>30, :next_time=>time, :timezone=>'UTC')
|
86
82
|
|
87
83
|
t01 = sc.poll(:alive_time=>86400, :now=>time)
|
88
84
|
t01.should == nil
|
@@ -90,7 +86,6 @@ describe ScheduleCollection do
|
|
90
86
|
t02 = sc.poll(:alive_time=>86400, :now=>time+30)
|
91
87
|
t02.class.should == Task
|
92
88
|
t02.key.should == 'sched01'
|
93
|
-
t02.type.should == 't01'
|
94
89
|
t02.scheduled_time.should == time
|
95
90
|
t02.delay.should == 30
|
96
91
|
|
@@ -102,38 +97,84 @@ describe ScheduleCollection do
|
|
102
97
|
t04 = sc.poll(:alive_time=>86400, :now=>time+3630)
|
103
98
|
t04.class.should == Task
|
104
99
|
t04.key.should == 'sched01'
|
105
|
-
t04.type.should == 't01'
|
106
100
|
t04.scheduled_time.should == time+3600
|
107
101
|
t04.delay.should == 30
|
108
102
|
end
|
109
103
|
|
104
|
+
it 'only_keys' do
|
105
|
+
time = 1323820800 # 2011-12-14 00:00:00 UTC
|
106
|
+
|
107
|
+
s01 = sc.add('sched01', :cron=>"0 * * * *", :delay=>0, :next_time=>time, :timezone=>'UTC')
|
108
|
+
|
109
|
+
t01 = sc.poll(:alive_time=>86400, :now=>time, :only_keys=>['sched02'])
|
110
|
+
t01.should == nil
|
111
|
+
|
112
|
+
s02 = sc.add('sched02', :cron=>"0 * * * *", :delay=>0, :next_time=>time, :timezone=>'UTC')
|
113
|
+
|
114
|
+
t02 = sc.poll(:alive_time=>86400, :now=>time, :only_keys=>['sched02'])
|
115
|
+
t02.class.should == Task
|
116
|
+
t02.key.should == 'sched02'
|
117
|
+
t02.scheduled_time.should == time
|
118
|
+
t02.delay.should == 0
|
119
|
+
|
120
|
+
t01 = sc.poll(:alive_time=>86400, :now=>time, :only_keys=>['sched02', 'sched01'])
|
121
|
+
t01.class.should == Task
|
122
|
+
t01.key.should == 'sched01'
|
123
|
+
t01.scheduled_time.should == time
|
124
|
+
t01.delay.should == 0
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'update_data' do
|
128
|
+
time = 1323820800 # 2011-12-14 00:00:00 UTC
|
129
|
+
|
130
|
+
s01 = sc.add('sched01', :cron=>"* * * * *", :data=>{'k'=>1}, :next_time=>time)
|
131
|
+
|
132
|
+
t01 = sc.poll(:alive_time=>120, :now=>time)
|
133
|
+
t01.data.should == {'k'=>1}
|
134
|
+
|
135
|
+
t01.finish!(:update_data=>{'v'=>1})
|
136
|
+
|
137
|
+
t01 = sc.poll(:alive_time=>120, :now=>time+60)
|
138
|
+
t01.data.should == {'k'=>1, 'v'=>1}
|
139
|
+
|
140
|
+
t01.finish!
|
141
|
+
|
142
|
+
t01 = sc.poll(:alive_time=>120, :now=>time+60*2)
|
143
|
+
t01.data.should == {'k'=>1, 'v'=>1}
|
144
|
+
|
145
|
+
t01.finish!(:update_data=>{'k'=>2})
|
146
|
+
|
147
|
+
t01 = sc.poll(:alive_time=>120, :now=>time+60*3)
|
148
|
+
t01.data.should == {'k'=>2, 'v'=>1}
|
149
|
+
end
|
150
|
+
|
110
151
|
it 'invalid cron format' do
|
111
152
|
lambda {
|
112
|
-
sc.add('sched01',
|
153
|
+
sc.add('sched01', :cron=>'???')
|
113
154
|
}.should raise_error ArgumentError
|
114
155
|
|
115
156
|
lambda {
|
116
|
-
sc.add('sched01',
|
157
|
+
sc.add('sched01', :cron=>'* * * * * *')
|
117
158
|
}.should raise_error ArgumentError
|
118
159
|
end
|
119
160
|
|
120
161
|
it 'fail duplicated add' do
|
121
|
-
sc.add('sched01',
|
162
|
+
sc.add('sched01', :cron=>"0 * * * *")
|
122
163
|
lambda {
|
123
|
-
sc.add('sched01',
|
164
|
+
sc.add('sched01', :cron=>"0 * * * *")
|
124
165
|
}.should raise_error AlreadyExistsError
|
125
166
|
|
126
167
|
sc['sched01'].delete!
|
127
168
|
|
128
|
-
sc.add('sched01',
|
169
|
+
sc.add('sched01', :cron=>"0 * * * *")
|
129
170
|
end
|
130
171
|
|
131
172
|
it 'list' do
|
132
173
|
time = 1323820800 # 2011-12-14 00:00:00 UTC
|
133
174
|
|
134
|
-
sc.add('sched01',
|
135
|
-
sc.add('sched02',
|
136
|
-
sc.add('sched03',
|
175
|
+
sc.add('sched01', :cron=>"0 * * * *", :next_time=>time, :delay=>1)
|
176
|
+
sc.add('sched02', :cron=>"0 * * * *", :next_time=>time, :delay=>2)
|
177
|
+
sc.add('sched03', :cron=>"0 * * * *", :next_time=>time, :delay=>3, :next_run_time=>time+3600)
|
137
178
|
|
138
179
|
a = []
|
139
180
|
sc.list {|s|
|
@@ -144,7 +185,6 @@ describe ScheduleCollection do
|
|
144
185
|
s01 = a.shift
|
145
186
|
s01.class.should == ScheduleWithMetadata
|
146
187
|
s01.key.should == 'sched01'
|
147
|
-
s01.type.should == 't01'
|
148
188
|
s01.cron.should == '0 * * * *'
|
149
189
|
s01.delay.should == 1
|
150
190
|
s01.next_time.should == time
|
@@ -153,7 +193,6 @@ describe ScheduleCollection do
|
|
153
193
|
s02 = a.shift
|
154
194
|
s02.class.should == ScheduleWithMetadata
|
155
195
|
s02.key.should == 'sched02'
|
156
|
-
s02.type.should == 't02'
|
157
196
|
s02.cron.should == '0 * * * *'
|
158
197
|
s02.delay.should == 2
|
159
198
|
s02.next_time.should == time
|
@@ -162,7 +201,6 @@ describe ScheduleCollection do
|
|
162
201
|
s03 = a.shift
|
163
202
|
s03.class.should == ScheduleWithMetadata
|
164
203
|
s03.key.should == 'sched03'
|
165
|
-
s03.type.should == 't03'
|
166
204
|
s03.cron.should == '0 * * * *'
|
167
205
|
s03.delay.should == 3
|
168
206
|
s03.next_time.should == time
|
data/spec/worker_spec.rb
CHANGED
@@ -18,7 +18,7 @@ class TestHandler < PerfectSched::Application::Base
|
|
18
18
|
end
|
19
19
|
|
20
20
|
class TestApp < PerfectSched::Application::Dispatch
|
21
|
-
route '
|
21
|
+
route 'key' => TestHandler
|
22
22
|
end
|
23
23
|
|
24
24
|
describe Worker do
|
@@ -43,7 +43,7 @@ describe Worker do
|
|
43
43
|
|
44
44
|
it 'run' do
|
45
45
|
TestHandler.any_instance.should_receive(:run).once
|
46
|
-
add('key',
|
46
|
+
add('key', {:cron=>'* * * * *', :next_time=>Time.now.to_i-60})
|
47
47
|
sleep 2
|
48
48
|
end
|
49
49
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perfectsched
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cron-spec
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -24,10 +24,18 @@ dependencies:
|
|
24
24
|
version: 0.1.2
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
|
-
version_requirements:
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.1.2
|
33
|
+
- - <=
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 0.1.2
|
28
36
|
- !ruby/object:Gem::Dependency
|
29
37
|
name: sequel
|
30
|
-
requirement:
|
38
|
+
requirement: !ruby/object:Gem::Requirement
|
31
39
|
none: false
|
32
40
|
requirements:
|
33
41
|
- - ~>
|
@@ -35,10 +43,15 @@ dependencies:
|
|
35
43
|
version: 3.26.0
|
36
44
|
type: :runtime
|
37
45
|
prerelease: false
|
38
|
-
version_requirements:
|
46
|
+
version_requirements: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ~>
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: 3.26.0
|
39
52
|
- !ruby/object:Gem::Dependency
|
40
53
|
name: tzinfo
|
41
|
-
requirement:
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
42
55
|
none: false
|
43
56
|
requirements:
|
44
57
|
- - ~>
|
@@ -46,10 +59,15 @@ dependencies:
|
|
46
59
|
version: 0.3.29
|
47
60
|
type: :runtime
|
48
61
|
prerelease: false
|
49
|
-
version_requirements:
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ~>
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.3.29
|
50
68
|
- !ruby/object:Gem::Dependency
|
51
69
|
name: perfectqueue
|
52
|
-
requirement:
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
53
71
|
none: false
|
54
72
|
requirements:
|
55
73
|
- - ~>
|
@@ -57,10 +75,15 @@ dependencies:
|
|
57
75
|
version: 0.8.5
|
58
76
|
type: :runtime
|
59
77
|
prerelease: false
|
60
|
-
version_requirements:
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ~>
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 0.8.5
|
61
84
|
- !ruby/object:Gem::Dependency
|
62
85
|
name: rake
|
63
|
-
requirement:
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
64
87
|
none: false
|
65
88
|
requirements:
|
66
89
|
- - ~>
|
@@ -68,10 +91,15 @@ dependencies:
|
|
68
91
|
version: 0.9.2
|
69
92
|
type: :development
|
70
93
|
prerelease: false
|
71
|
-
version_requirements:
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ~>
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 0.9.2
|
72
100
|
- !ruby/object:Gem::Dependency
|
73
101
|
name: rspec
|
74
|
-
requirement:
|
102
|
+
requirement: !ruby/object:Gem::Requirement
|
75
103
|
none: false
|
76
104
|
requirements:
|
77
105
|
- - ~>
|
@@ -79,10 +107,15 @@ dependencies:
|
|
79
107
|
version: 2.10.0
|
80
108
|
type: :development
|
81
109
|
prerelease: false
|
82
|
-
version_requirements:
|
110
|
+
version_requirements: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ~>
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 2.10.0
|
83
116
|
- !ruby/object:Gem::Dependency
|
84
117
|
name: simplecov
|
85
|
-
requirement:
|
118
|
+
requirement: !ruby/object:Gem::Requirement
|
86
119
|
none: false
|
87
120
|
requirements:
|
88
121
|
- - ~>
|
@@ -90,10 +123,15 @@ dependencies:
|
|
90
123
|
version: 0.5.4
|
91
124
|
type: :development
|
92
125
|
prerelease: false
|
93
|
-
version_requirements:
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ~>
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.5.4
|
94
132
|
- !ruby/object:Gem::Dependency
|
95
133
|
name: sqlite3
|
96
|
-
requirement:
|
134
|
+
requirement: !ruby/object:Gem::Requirement
|
97
135
|
none: false
|
98
136
|
requirements:
|
99
137
|
- - ~>
|
@@ -101,7 +139,12 @@ dependencies:
|
|
101
139
|
version: 1.3.3
|
102
140
|
type: :development
|
103
141
|
prerelease: false
|
104
|
-
version_requirements:
|
142
|
+
version_requirements: !ruby/object:Gem::Requirement
|
143
|
+
none: false
|
144
|
+
requirements:
|
145
|
+
- - ~>
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: 1.3.3
|
105
148
|
description: Highly available distributed cron built on RDBMS
|
106
149
|
email: frsyuki@gmail.com
|
107
150
|
executables:
|
@@ -163,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
163
206
|
version: '0'
|
164
207
|
requirements: []
|
165
208
|
rubyforge_project:
|
166
|
-
rubygems_version: 1.8.
|
209
|
+
rubygems_version: 1.8.23
|
167
210
|
signing_key:
|
168
211
|
specification_version: 3
|
169
212
|
summary: Highly available distributed cron built on RDBMS
|