updater 0.2.1 → 0.2.2
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/VERSION +1 -1
- data/lib/updater/update.rb +47 -17
- data/lib/updater/worker.rb +46 -14
- data/spec/worker_spec.rb +39 -0
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.2
|
data/lib/updater/update.rb
CHANGED
@@ -12,7 +12,7 @@ module Updater
|
|
12
12
|
property :ident, Yaml
|
13
13
|
property :method, String
|
14
14
|
property :finder, String
|
15
|
-
property :args, Object
|
15
|
+
property :args, Object, :lazy=>false
|
16
16
|
property :time, Integer
|
17
17
|
property :name, String
|
18
18
|
property :lock_name, String
|
@@ -130,7 +130,13 @@ module Updater
|
|
130
130
|
hash[:ident] = ident_for(target,finder,finder_args)
|
131
131
|
hash[:finder] = finder || :get
|
132
132
|
hash[:time] = time
|
133
|
-
create(hash.merge(options))
|
133
|
+
ret = create(hash.merge(options))
|
134
|
+
Process.kill('USR1',pid) if pid
|
135
|
+
ret
|
136
|
+
rescue Errno::ESRCH
|
137
|
+
@pid = nil
|
138
|
+
puts "PID invalid"
|
139
|
+
#log this as well
|
134
140
|
end
|
135
141
|
|
136
142
|
# like +at+ but with time as time.now. Generally this will be used to run a long running operation in
|
@@ -192,12 +198,32 @@ module Updater
|
|
192
198
|
all(:time.gt=>time.now.to_i)
|
193
199
|
end
|
194
200
|
|
201
|
+
#Sets the process id of the worker process if known. If this
|
202
|
+
#is set then an attempt will be made to signal the worker any
|
203
|
+
#time a new update is made.
|
204
|
+
#
|
205
|
+
#If pid is not set, or is set to nil then the scheduleing program
|
206
|
+
#is responcible for waking-up a potentially sleeping worker process
|
207
|
+
#in another way.
|
208
|
+
def pid=(p)
|
209
|
+
return @pid = nil unless p #tricky assignment in return
|
210
|
+
@pid = Integer("#{p}")
|
211
|
+
Process::kill 0, @pid
|
212
|
+
@pid
|
213
|
+
rescue Errno::ESRCH, ArgumentError
|
214
|
+
raise ArgumentError "PID was invalid"
|
215
|
+
end
|
216
|
+
|
217
|
+
def pid
|
218
|
+
@pid
|
219
|
+
end
|
220
|
+
|
195
221
|
#This returns a set of update requests.
|
196
222
|
#The first parameter is the maximum number to return (get a few other workers may be in compitition)
|
197
223
|
#The second optional parameter is a list of options to be past to DataMapper.
|
198
224
|
def worker_set(limit = 5, options={})
|
199
225
|
#TODO: add priority to this.
|
200
|
-
options = {:limit=>limit, :order=>[:time.
|
226
|
+
options = {:lock_name=>nil,:limit=>limit, :order=>[:time.asc]}.merge(options)
|
201
227
|
current.all(options)
|
202
228
|
end
|
203
229
|
|
@@ -208,24 +234,28 @@ module Updater
|
|
208
234
|
#Gets a single gob form the queue, locks and runs it.
|
209
235
|
def work_off(worker)
|
210
236
|
updates = worker_set
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
t = u.run_with_lock(worker)
|
223
|
-
return queue_time unless nil == t
|
237
|
+
unless updates.empty?
|
238
|
+
#concept copied form delayed_job. If there are a number of
|
239
|
+
#different processes working on the queue, the niave approch
|
240
|
+
#would result in every instance trying to lock the same record.
|
241
|
+
#by shuffleing our results we greatly reduce the chances that
|
242
|
+
#multilpe workers try to lock the same process
|
243
|
+
updates = updates.to_a.sort_by{rand()}
|
244
|
+
updates.each do |u|
|
245
|
+
t = u.run_with_lock(worker)
|
246
|
+
break unless nil == t
|
247
|
+
end
|
224
248
|
end
|
249
|
+
rescue DataObjects::ConnectionError
|
250
|
+
sleep 0.1
|
251
|
+
retry
|
252
|
+
ensure
|
253
|
+
worker.clear_locks
|
254
|
+
return queue_time
|
225
255
|
end
|
226
256
|
|
227
257
|
def queue_time
|
228
|
-
nxt = self.first(:time.not=>nil, :order=>[:time.
|
258
|
+
nxt = self.first(:time.not=>nil,:lock_name=>nil, :order=>[:time.asc])
|
229
259
|
return nil unless nxt
|
230
260
|
return 0 if nxt.time <= time.now.to_i
|
231
261
|
return nxt.time - time.now.to_i
|
data/lib/updater/worker.rb
CHANGED
@@ -19,24 +19,19 @@ module Updater
|
|
19
19
|
|
20
20
|
def start
|
21
21
|
say "*** Starting job worker #{@name}"
|
22
|
-
t =
|
23
|
-
loop do
|
24
|
-
delay = Update.work_off(self)
|
25
|
-
break if $exit
|
26
|
-
sleep delay
|
27
|
-
break if $exit
|
28
|
-
end
|
29
|
-
clear_locks
|
30
|
-
end
|
22
|
+
@t = run_job_loop
|
31
23
|
|
32
|
-
trap('TERM') { terminate_with t }
|
33
|
-
trap('INT') { terminate_with t }
|
24
|
+
trap('TERM') { terminate_with @t }
|
25
|
+
trap('INT') { terminate_with @t }
|
34
26
|
|
35
27
|
trap('USR1') do
|
36
|
-
|
37
|
-
|
28
|
+
old_proc = trap('USR1','IGNORE')
|
29
|
+
run_loop
|
30
|
+
trap('USR1',old_proc)
|
38
31
|
end
|
39
32
|
|
33
|
+
Thread.pass
|
34
|
+
|
40
35
|
sleep unless $exit
|
41
36
|
end
|
42
37
|
|
@@ -49,12 +44,49 @@ module Updater
|
|
49
44
|
Update.all(:lock_name=>@name).update(:lock_name=>nil)
|
50
45
|
end
|
51
46
|
|
47
|
+
def stop
|
48
|
+
raise RuntimeError unless @t
|
49
|
+
terminate_with @t
|
50
|
+
end
|
51
|
+
|
52
|
+
def run_loop
|
53
|
+
if @t.alive?
|
54
|
+
@t.wakeup #calling run here is a Bad Idea
|
55
|
+
else
|
56
|
+
say " ~~ Restarting Job Loop"
|
57
|
+
@t = run_job_loop
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
52
61
|
private
|
53
62
|
|
63
|
+
def run_job_loop
|
64
|
+
Thread.new do
|
65
|
+
loop do
|
66
|
+
begin
|
67
|
+
delay = Update.work_off(self)
|
68
|
+
break if $exit
|
69
|
+
if delay
|
70
|
+
sleep delay
|
71
|
+
else
|
72
|
+
sleep
|
73
|
+
end
|
74
|
+
break if $exit
|
75
|
+
rescue
|
76
|
+
say "Caught exception in Job Loop"
|
77
|
+
sleep 0.1
|
78
|
+
retry
|
79
|
+
end
|
80
|
+
end
|
81
|
+
say "Worker thread exiting!"
|
82
|
+
clear_locks
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
54
86
|
def terminate_with(t)
|
55
87
|
say "Exiting..."
|
56
88
|
$exit = true
|
57
|
-
t.run
|
89
|
+
t.run if t.alive?
|
58
90
|
say "Forcing Shutdown" unless status = t.join(15) #Nasty inline assignment
|
59
91
|
clear_locks
|
60
92
|
exit status ? 0 : 1
|
data/spec/worker_spec.rb
CHANGED
@@ -17,6 +17,43 @@ describe Worker do
|
|
17
17
|
Worker.new.name.should be_a String
|
18
18
|
end
|
19
19
|
|
20
|
+
describe "loop thread control:" do
|
21
|
+
|
22
|
+
class Foo
|
23
|
+
include DataMapper::Resource
|
24
|
+
|
25
|
+
property :id, Serial
|
26
|
+
property :name, String
|
27
|
+
|
28
|
+
def bar(*args)
|
29
|
+
Foo.bar(:instance,*args)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
Foo.auto_migrate!
|
35
|
+
|
36
|
+
specify "The loop should run when the worker is started" do
|
37
|
+
pending
|
38
|
+
worker = Worker.new(:quiet=>true, :name=>"testing")
|
39
|
+
Update.should_receive(:work_off).with(worker).once.and_return(nil)
|
40
|
+
t = Thread.new do
|
41
|
+
worker.start
|
42
|
+
end
|
43
|
+
t.run
|
44
|
+
worker.stop
|
45
|
+
t.kill unless t.join(0.1) #you've got 0.1 seconds to finish or die
|
46
|
+
end
|
47
|
+
|
48
|
+
specify "The loop should run with USR1 signal" do
|
49
|
+
pending
|
50
|
+
t = Thread.new do
|
51
|
+
worker.start
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
20
57
|
end
|
21
58
|
|
22
59
|
describe "working off jobs:" do
|
@@ -63,6 +100,8 @@ describe "working off jobs:" do
|
|
63
100
|
it "should return the number of seconds till the next job if there are no jobs to be run" do
|
64
101
|
Timecop.freeze(Time.now)
|
65
102
|
u1 = Update.at(Time.now + 30, Foo,:bar,[:arg1])
|
103
|
+
Update.at(Time.now + 35, Foo,:bar,[:arg1])
|
104
|
+
Update.at(Time.now + 1000, Foo,:bar,[:arg1])
|
66
105
|
Update.work_off(Worker.new(:name=>"first", :quiet=>true)).should == 30
|
67
106
|
end
|
68
107
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: updater
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John F. Miller
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-24 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|