updater 0.3.2 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/updater/fork_worker.rb +24 -12
- data/lib/updater/orm/datamapper.rb +36 -9
- data/lib/updater/orm/orm.rb +16 -0
- data/lib/updater/setup.rb +72 -15
- data/lib/updater/update.rb +41 -6
- data/spec/named_request_spec.rb +25 -5
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.0
|
data/lib/updater/fork_worker.rb
CHANGED
@@ -35,7 +35,7 @@ module Updater
|
|
35
35
|
logger.info "Max Workers set to #{@max_workers}"
|
36
36
|
@timeout = options[:timeout] || 60
|
37
37
|
logger.info "Timeout set to #{@timeout} sec."
|
38
|
-
@current_workers = 1
|
38
|
+
@current_workers = 1 #we will actually add this worker the first time through the master loop
|
39
39
|
@workers = {} #key is pid value is worker class
|
40
40
|
@uptime = Time.now
|
41
41
|
@downtime = Time.now
|
@@ -92,10 +92,9 @@ module Updater
|
|
92
92
|
# * :timeout : how long can a worker be inactive before being killed
|
93
93
|
# * :sockets: 0 or more IO objects that should wake up master to alert it that new data is availible
|
94
94
|
|
95
|
-
def start(
|
95
|
+
def start(options = {})
|
96
96
|
initial_setup(options) #need this for logger
|
97
97
|
logger.info "*** Starting Master Process***"
|
98
|
-
@stream = stream
|
99
98
|
logger.info "* Adding the first round of workers *"
|
100
99
|
maintain_worker_count
|
101
100
|
QUEUE_SIGS.each { |sig| trap_deferred(sig) }
|
@@ -121,13 +120,13 @@ module Updater
|
|
121
120
|
logger.fatal "10 consecutive errors! Abandoning Master process"
|
122
121
|
end
|
123
122
|
stop # gracefully shutdown all workers on our way out
|
124
|
-
logger.
|
123
|
+
logger.warn "-=-=-=- master process Exiting -=-=-=-\n\n"
|
125
124
|
end
|
126
125
|
|
127
126
|
def stop(graceful = true)
|
128
127
|
trap(:USR2,"IGNORE")
|
129
128
|
[:INT,:TERM].each {|signal| trap(signal,"DEFAULT") }
|
130
|
-
puts "Quitting. I need 30 seconds to stop my workers..."
|
129
|
+
puts "Quitting. I need 30 seconds to stop my workers..." unless @workers.empty?
|
131
130
|
limit = Time.now + 30
|
132
131
|
signal_each_worker(graceful ? :QUIT : :TERM)
|
133
132
|
until @workers.empty? || Time.now > limit
|
@@ -140,15 +139,26 @@ module Updater
|
|
140
139
|
def master_sleep
|
141
140
|
begin
|
142
141
|
timeout = calc_timeout
|
143
|
-
logger.debug { "Sleeping for #{timeout}" }
|
142
|
+
logger.debug { "Sleeping for #{timeout}" }
|
144
143
|
ready, _1, _2 = IO.select(@wakeup_set, nil, nil, timeout)
|
145
|
-
return unless ready && ready.first #just wakeup and run maintance
|
146
|
-
|
144
|
+
return unless ready && ready.first #timeout hit, just wakeup and run maintance
|
145
|
+
add_connection(ready.first) and return if ready.first.respond_to?(:accept) #open a new incomming connection
|
146
|
+
@signal_queue << :DATA unless ready.first == @self_pipe.first
|
147
147
|
loop {ready.first.read_nonblock(16 * 1024)}
|
148
|
+
rescue EOFError #somebody closed thier connection
|
149
|
+
logger.info "closed socket connection"
|
150
|
+
@wakeup_set.delete ready.first
|
151
|
+
ready.first.close
|
148
152
|
rescue Errno::EAGAIN, Errno::EINTR
|
149
153
|
end
|
150
154
|
end
|
151
155
|
|
156
|
+
def add_connection(server)
|
157
|
+
@wakeup_set << server.accept_nonblock
|
158
|
+
logger.info "opened socket connection: [#{@wakeup_set.last.addr.join(', ')}]"
|
159
|
+
rescue Errno::EAGAIN, Errno::EINTR
|
160
|
+
end
|
161
|
+
|
152
162
|
def calc_timeout
|
153
163
|
Time.now - [@uptime, @downtime].max < @timeout ? @timeout / 8 : 2*@timeout
|
154
164
|
end
|
@@ -219,6 +229,7 @@ module Updater
|
|
219
229
|
|
220
230
|
def add_worker(worker_number)
|
221
231
|
worker = WorkerMonitor.new(worker_number,Updater::Util.tempio)
|
232
|
+
Update.orm.before_fork
|
222
233
|
pid = Process.fork do
|
223
234
|
fork_cleanup
|
224
235
|
self.new(@pipe,worker).run
|
@@ -229,6 +240,7 @@ module Updater
|
|
229
240
|
|
230
241
|
def fork_cleanup
|
231
242
|
QUEUE_SIGS.each { |signal| trap(signal,"IGNORE") }
|
243
|
+
Update.orm.after_fork
|
232
244
|
if @self_pipe !=nil
|
233
245
|
@self_pipe.each {|io| io.close}
|
234
246
|
end
|
@@ -327,8 +339,8 @@ module Updater
|
|
327
339
|
wait_for(delay) if @continue
|
328
340
|
rescue Exception=> e
|
329
341
|
say "Caught exception in Job Loop"
|
330
|
-
say e.
|
331
|
-
say "||=========\n|| Backtrace\n|| " + e.backtrace.join("\n|| ") + "\n||========="
|
342
|
+
say e.inspect
|
343
|
+
say "\n||=========\n|| Backtrace\n|| " + e.backtrace.join("\n|| ") + "\n||========="
|
332
344
|
Update.clear_locks(self)
|
333
345
|
exit; #die and be replaced by the master process
|
334
346
|
end
|
@@ -392,8 +404,8 @@ module Updater
|
|
392
404
|
#need to wait for another job
|
393
405
|
t = Time.now + delay
|
394
406
|
while Time.now < t && @continue
|
395
|
-
delay = [@timeout,t-Time.now].min
|
396
|
-
debug "No Jobs; #{name} sleeping for #{delay}: [#{@timeout},#{t - Time.now}].min"
|
407
|
+
delay = [@timeout/2,t-Time.now].min
|
408
|
+
debug "No Jobs; #{name} sleeping for #{delay}: [#{@timeout/2},#{t - Time.now}].min"
|
397
409
|
wakeup,_1,_2 = select([@stream],nil,nil,delay)
|
398
410
|
heartbeat
|
399
411
|
if wakeup
|
@@ -19,13 +19,13 @@ module Updater
|
|
19
19
|
storage_names[:default] = "updates"
|
20
20
|
|
21
21
|
property :id, Serial
|
22
|
-
property :time, Integer
|
23
|
-
property :target, Class
|
24
|
-
property :finder, String
|
25
|
-
property :finder_args, Yaml
|
22
|
+
property :time, Integer, :index=>true
|
23
|
+
property :target, Class, :index=>:for_target
|
24
|
+
property :finder, String, :index=>:for_target
|
25
|
+
property :finder_args, Yaml, :index=>:for_target
|
26
26
|
property :method, String
|
27
27
|
property :method_args, Object, :lazy=>false
|
28
|
-
property :name, String, :length=>255
|
28
|
+
property :name, String, :length=>255, :index=>true
|
29
29
|
property :lock_name, String
|
30
30
|
property :persistant, Boolean
|
31
31
|
|
@@ -112,6 +112,7 @@ module Updater
|
|
112
112
|
return nxt.time - tnow
|
113
113
|
end
|
114
114
|
|
115
|
+
#Returns the Locked Job or nil if no jobs were availible.
|
115
116
|
def lock_next(worker)
|
116
117
|
updates = worker_set
|
117
118
|
unless updates.empty?
|
@@ -124,6 +125,7 @@ module Updater
|
|
124
125
|
updates.each do |u|
|
125
126
|
return u if u.lock(worker)
|
126
127
|
end
|
128
|
+
return nil
|
127
129
|
end
|
128
130
|
rescue DataObjects::ConnectionError
|
129
131
|
sleep 0.1
|
@@ -140,7 +142,32 @@ module Updater
|
|
140
142
|
end
|
141
143
|
|
142
144
|
def for(mytarget, myfinder, myfinder_args, myname=nil)
|
143
|
-
|
145
|
+
search = all(
|
146
|
+
:target=>mytarget,
|
147
|
+
:finder=>myfinder,
|
148
|
+
:finder_args=>myfinder_args,
|
149
|
+
:lock_name=>nil
|
150
|
+
)
|
151
|
+
myname ? search.all(:name=>myname ) : search
|
152
|
+
end
|
153
|
+
|
154
|
+
#For the server only, setup the connection to the database
|
155
|
+
def setup(options)
|
156
|
+
::DataMapper.logger = options.delete(:logger)
|
157
|
+
::DataMapper.setup(:default,options)
|
158
|
+
end
|
159
|
+
|
160
|
+
# For pooled connections it is necessary to empty the pool of the parents connections so that they
|
161
|
+
# do not comtiminate the child pool. Note that while Datamapper is thread safe, it is not safe accross a process fork.
|
162
|
+
def before_fork
|
163
|
+
return unless (defined? ::DataObjects::Pooling)
|
164
|
+
return if ::DataMapper.repository.adapter.kind_of?(::DataMapper::Adapters::Sqlite3Adapter)
|
165
|
+
::DataMapper.logger.debug "+-+-+-+-+ Cleaning up connection pool (#{::DataObjects::Pooling.pools.length}) +-+-+-+-+"
|
166
|
+
::DataObjects::Pooling.pools.each {|p| p.dispose}
|
167
|
+
end
|
168
|
+
|
169
|
+
def after_fork
|
170
|
+
|
144
171
|
end
|
145
172
|
|
146
173
|
private
|
@@ -152,7 +179,7 @@ module Updater
|
|
152
179
|
options = {:lock_name=>nil,:limit=>limit, :order=>[:time.asc]}.merge(options)
|
153
180
|
current.all(options)
|
154
181
|
end
|
155
|
-
|
182
|
+
|
156
183
|
def lock
|
157
184
|
|
158
185
|
end
|
@@ -168,8 +195,8 @@ module Updater
|
|
168
195
|
belongs_to :caller, :model=>Updater::ORM::DataMapper, :child_key=>[:caller_id]
|
169
196
|
belongs_to :target, :model=>Updater::ORM::DataMapper, :child_key=>[:target_id]
|
170
197
|
|
171
|
-
property :params, Object, :
|
172
|
-
property :occasion, String, :
|
198
|
+
property :params, Object, :required=>false
|
199
|
+
property :occasion, String, :required=>true
|
173
200
|
end
|
174
201
|
|
175
202
|
end#ORM
|
data/lib/updater/orm/orm.rb
CHANGED
@@ -217,6 +217,22 @@ module Updater
|
|
217
217
|
NotImplementedError
|
218
218
|
end
|
219
219
|
|
220
|
+
# This method is the generic way to setup the datastore. Options is a hash one of whose fields
|
221
|
+
# will be :logger, the logger instance to pass on to the ORM. The rest of the options are ORM
|
222
|
+
# spesific. The function should prepair a connection to the datastore using the given options.
|
223
|
+
# If the connection cannot be prepaired then an appropriate error should be raised.
|
224
|
+
def setup(options)
|
225
|
+
NotImplementedError
|
226
|
+
end
|
227
|
+
|
228
|
+
# This method is called by the child before a fork call. It allows the ORM to clean up any connections
|
229
|
+
# Made by the parent and establish new connections if necessary.
|
230
|
+
def before_fork
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
def after_fork
|
235
|
+
|
220
236
|
# Optional, but strongly recomended.
|
221
237
|
#
|
222
238
|
# For any datastore that permits, return and Array of all delayed, chained, and current but not locked jobs that reference
|
data/lib/updater/setup.rb
CHANGED
@@ -14,6 +14,10 @@ module Updater
|
|
14
14
|
new(config_file).stop
|
15
15
|
end
|
16
16
|
|
17
|
+
def client_setup(options = {})
|
18
|
+
new(config_file, options).client_setup
|
19
|
+
end
|
20
|
+
|
17
21
|
def monitor
|
18
22
|
|
19
23
|
end
|
@@ -27,44 +31,84 @@ module Updater
|
|
27
31
|
end
|
28
32
|
end
|
29
33
|
|
30
|
-
ROOT = File.dirname(self.config_file)
|
34
|
+
ROOT = File.dirname(self.config_file || Dir.pwd)
|
31
35
|
|
32
|
-
|
36
|
+
#extended used for clients who wnat to override parameters
|
37
|
+
def initialize(file_or_hash, extended = {})
|
33
38
|
@options = file_or_hash.kind_of?(Hash) ? file_or_hash : load_file(file_or_hash)
|
39
|
+
@options.merge(extended)
|
34
40
|
@options[:pid_file] ||= File.join(ROOT,'updater.pid')
|
35
41
|
@options[:host] ||= "localhost"
|
36
|
-
@logger = Logger.new(@options[:log_file] || STDOUT)
|
42
|
+
@logger = @options[:logger] || Logger.new(@options[:log_file] || STDOUT)
|
37
43
|
level = Logger::SEV_LABEL.index(@options[:log_level].upcase) if @options[:log_level]
|
38
44
|
@logger.level = level || Logger::WARN
|
39
45
|
end
|
40
46
|
|
41
47
|
def start
|
42
|
-
@logger.warn "Starting Loop"
|
43
48
|
pid = Process.fork do
|
44
49
|
_start
|
45
50
|
end
|
46
|
-
@logger.warn "
|
51
|
+
@logger.warn "Successfully started Master Loop at pid #{pid}"
|
52
|
+
puts "Job Queue Processor Started at PID: #{pid}"
|
47
53
|
end
|
48
54
|
|
49
55
|
def stop
|
50
56
|
Process.kill("TERM",File.read(@options[:pid_file]).to_i)
|
51
57
|
end
|
52
58
|
|
53
|
-
|
59
|
+
# The client is responcible for loading classes and making connections. We will simply setup the Updater spesifics
|
60
|
+
def client_setup
|
61
|
+
set_orm
|
62
|
+
|
63
|
+
if @options[:socket] && File.exists?(@options[:socket])
|
64
|
+
Updater::Update.socket = UNIXSocket.new(@options[:socket])
|
65
|
+
elsif @options[:udp]
|
66
|
+
socket = UDPSocket.new()
|
67
|
+
socket.connect(@options[:host],@options[:udp])
|
68
|
+
Updater::Update.socket = socket
|
69
|
+
elsif @options[:tcp]
|
70
|
+
Updater::Update.socket = TCPSocket.new(@options[:host],@options[:tcp])
|
71
|
+
elsif @options[:remote]
|
72
|
+
raise NotImplimentedError #For future Authenticated Http Rest Server
|
73
|
+
end
|
74
|
+
|
75
|
+
#set PID
|
76
|
+
if File.exists? @options[:pid_file]
|
77
|
+
Updater::Update.pid = File.read(@options[:pid_file]).strip
|
78
|
+
end
|
79
|
+
|
54
80
|
|
55
81
|
end
|
56
82
|
|
57
83
|
private
|
58
84
|
|
85
|
+
def set_orm
|
86
|
+
#don't setup twice. Client setup might call this as part of server setup in which case it is already done
|
87
|
+
return false if Updater::Update.orm
|
88
|
+
orm = @options[:orm] || "datamapper"
|
89
|
+
case orm.downcase
|
90
|
+
when "datamapper"
|
91
|
+
require 'updater/orm/datamapper'
|
92
|
+
Updater::Update.orm = ORM::DataMapper
|
93
|
+
when "mongodb"
|
94
|
+
require 'updater/orm/mongodb'
|
95
|
+
Updater::Update.orm = ORM::MongoDB
|
96
|
+
when "activerecord"
|
97
|
+
require 'updater/orm/activerecord'
|
98
|
+
Updater::Update.orm = ORM::ActiveRecord
|
99
|
+
else
|
100
|
+
require "update/orm/#{orm}"
|
101
|
+
Updater::Update.orm = Object.const_get("ORM").const_get(orm.capitalize)
|
102
|
+
end
|
103
|
+
@logger.info "Data store '#{orm}' selected"
|
104
|
+
end
|
105
|
+
|
59
106
|
def _start
|
60
107
|
#set ORM
|
61
|
-
|
62
|
-
Updater::Update.orm = ORM::DataMapper
|
63
|
-
|
108
|
+
set_orm
|
64
109
|
#init DataStore
|
65
|
-
|
66
|
-
|
67
|
-
|
110
|
+
default_options = {:adapter=>'sqlite3', :database=>'./default.db'}
|
111
|
+
Updater::Update.orm.setup((@options[:database] || @options[:orm_setup] || default_options).merge(:logger=>@logger))
|
68
112
|
#load Models
|
69
113
|
|
70
114
|
models = @options[:models] || Dir.glob('./app/models/**/*.rb')
|
@@ -73,11 +117,13 @@ module Updater
|
|
73
117
|
end
|
74
118
|
|
75
119
|
#establish Connections
|
120
|
+
@options[:host] ||= 'localhost'
|
76
121
|
#Unix Socket -- name at @options[:socket]
|
77
122
|
if @options[:socket]
|
78
123
|
File.unlink @options[:socket] if File.exists? @options[:socket]
|
79
124
|
@options[:sockets] ||= []
|
80
125
|
@options[:sockets] << UNIXServer.new(@options[:socket])
|
126
|
+
@logger.info "Now listening on UNIX Socket: #{@options[:socket]}"
|
81
127
|
end
|
82
128
|
|
83
129
|
#UDP potentially unsafe user monitor server for Authenticated Connections (TODO)
|
@@ -86,28 +132,39 @@ module Updater
|
|
86
132
|
udp = UDPSocket.new
|
87
133
|
udp.bind(@options[:host],@options[:udp])
|
88
134
|
@options[:sockets] << udp
|
135
|
+
@logger.info "Now listening for UDP: #{@options[:host]}:#{@options[:udp]}"
|
89
136
|
end
|
90
137
|
|
91
138
|
#TCP Unsafe user monitor server for Authenticated Connections (TODO)
|
92
139
|
if @options[:tcp]
|
93
140
|
@options[:sockets] ||= []
|
94
141
|
@options[:sockets] << TCPServer.new(@options[:host],@options[:tcp])
|
142
|
+
@logger.info "Now listening for TCP: #{@options[:host]}:#{@options[:tcp]}"
|
95
143
|
end
|
96
144
|
|
97
145
|
#Log PID
|
98
146
|
File.open(@options[:pid_file],'w') { |f| f.write(Process.pid.to_s)}
|
147
|
+
|
148
|
+
client_setup
|
149
|
+
|
99
150
|
#start Worker
|
100
|
-
|
101
|
-
|
151
|
+
worker = @options[:worker] || 'fork' #todo make this line windows safe
|
152
|
+
require "updater/#{worker}_worker"
|
153
|
+
worker_class = Updater.const_get("#{worker.capitalize}Worker")
|
102
154
|
worker_class.logger = @logger
|
155
|
+
@logger.info "Using #{worker_class.to_s} to run jobs:"
|
103
156
|
worker_class.start(@options)
|
157
|
+
File.unlink(@options[:pid_file])
|
158
|
+
File.unlink @options[:socket] if @options[:socket] && File.exists?(@options[:socket])
|
104
159
|
end
|
105
160
|
|
106
161
|
def load_file(file)
|
107
162
|
return {} if file.nil?
|
108
163
|
file = File.open(file) if file.kind_of?(String)
|
109
164
|
@config_file = File.expand_path(file.path)
|
110
|
-
YAML.load(ERB.new(
|
165
|
+
YAML.load(ERB.new(file.read).result(binding)) || {}
|
166
|
+
ensure
|
167
|
+
file.close
|
111
168
|
end
|
112
169
|
end
|
113
170
|
end
|
data/lib/updater/update.rb
CHANGED
@@ -22,7 +22,12 @@ module Updater
|
|
22
22
|
ensure
|
23
23
|
run_chain :success if ret
|
24
24
|
run_chain :ensure
|
25
|
-
|
25
|
+
begin
|
26
|
+
@orm.destroy unless @orm.persistant
|
27
|
+
rescue DataObjects::ConnectionError
|
28
|
+
sleep 0.1
|
29
|
+
retry
|
30
|
+
end
|
26
31
|
end
|
27
32
|
ret
|
28
33
|
end
|
@@ -33,7 +38,7 @@ module Updater
|
|
33
38
|
|
34
39
|
def target
|
35
40
|
target = @orm.finder.nil? ? @orm.target : @orm.target.send(@orm.finder,@orm.finder_args)
|
36
|
-
raise TargetMissingError, "Class:'#{@orm.target}' Finder:'#{@orm.finder}', Args:'#{@orm.finder_args.inspect}'" unless target
|
41
|
+
raise TargetMissingError, "Target missing --Class:'#{@orm.target}' Finder:'#{@orm.finder}', Args:'#{@orm.finder_args.inspect}'" unless target
|
37
42
|
target
|
38
43
|
end
|
39
44
|
|
@@ -49,17 +54,23 @@ module Updater
|
|
49
54
|
@orm.name
|
50
55
|
end
|
51
56
|
|
52
|
-
#This is the appropriate
|
57
|
+
#This is the appropriate value to use for a chanable field value
|
53
58
|
def id
|
54
59
|
@orm.id
|
55
60
|
end
|
56
61
|
|
62
|
+
def ==(other)
|
63
|
+
id = other.id
|
64
|
+
end
|
65
|
+
|
57
66
|
def persistant?
|
58
67
|
@orm.persistant
|
59
68
|
end
|
60
69
|
|
61
70
|
def inspect
|
62
71
|
"#<Updater::Update target=#{target.inspect} time=#{orm.time}>"
|
72
|
+
rescue TargetMissingError
|
73
|
+
"#<Updater::Update target=<missing> time=#{orm.time}>"
|
63
74
|
end
|
64
75
|
|
65
76
|
private
|
@@ -93,6 +104,9 @@ module Updater
|
|
93
104
|
chains.each do |job|
|
94
105
|
Update.new(job.target).run(self,job.params)
|
95
106
|
end
|
107
|
+
rescue NameError
|
108
|
+
puts @orm.inspect
|
109
|
+
raise
|
96
110
|
end
|
97
111
|
|
98
112
|
class << self
|
@@ -100,6 +114,16 @@ module Updater
|
|
100
114
|
#This attribute must be set to some ORM that will persist the data
|
101
115
|
attr_accessor :orm
|
102
116
|
|
117
|
+
#remove once Bug is discovered
|
118
|
+
def orm=(input)
|
119
|
+
raise ArgumentError, "Must set ORM to and appropriate class" unless input.kind_of? Class
|
120
|
+
@orm = input
|
121
|
+
end
|
122
|
+
|
123
|
+
# This is an open IO socket that will be writen to when a job is scheduled. If it is unset
|
124
|
+
# then @pid is signaled instead.
|
125
|
+
attr_accessor :socket
|
126
|
+
|
103
127
|
#Gets a single job form the queue, locks and runs it. it returns the number of second
|
104
128
|
#Until the next job is scheduled, or 0 is there are more current jobs, or nil if there
|
105
129
|
#are no jobs scheduled.
|
@@ -198,8 +222,12 @@ module Updater
|
|
198
222
|
# Advanced: This method allows values to be passed directly to the ORM layer's create method.
|
199
223
|
# use +at+ and friends for everyday use cases.
|
200
224
|
def schedule(hash)
|
201
|
-
new(@orm.create(hash))
|
225
|
+
r = new(@orm.create(hash))
|
202
226
|
signal_worker
|
227
|
+
r
|
228
|
+
rescue NoMethodError
|
229
|
+
raise ArgumentError, "ORM not initialized!" if @orm.nil?
|
230
|
+
raise
|
203
231
|
end
|
204
232
|
|
205
233
|
# Create a new job having the same charistics as the old, except that 'hash' will override the original.
|
@@ -237,7 +265,9 @@ module Updater
|
|
237
265
|
#
|
238
266
|
# <Array[Updater]> unless name is given then only a single [Updater] instance.
|
239
267
|
def for(target,name=nil)
|
240
|
-
|
268
|
+
target,finder,args = target_for(target)
|
269
|
+
ret = @orm.for(target,finder,args,name).map {|i| new(i)}
|
270
|
+
name ? ret.first : ret
|
241
271
|
end
|
242
272
|
|
243
273
|
#The time class used by Updater. See time=
|
@@ -286,6 +316,8 @@ module Updater
|
|
286
316
|
#is set then an attempt will be made to signal the worker any
|
287
317
|
#time a new update is made.
|
288
318
|
#
|
319
|
+
#The PID will not be signaled if @socket is availible, but should be set as a back-up
|
320
|
+
#
|
289
321
|
#If pid is not set, or is set to nil then the scheduleing program
|
290
322
|
#is responcible for waking-up a potentially sleeping worker process
|
291
323
|
#in another way.
|
@@ -295,6 +327,7 @@ module Updater
|
|
295
327
|
Process::kill 0, @pid
|
296
328
|
@pid
|
297
329
|
rescue Errno::ESRCH, ArgumentError
|
330
|
+
@pid = nil
|
298
331
|
raise ArgumentError, "PID was invalid"
|
299
332
|
end
|
300
333
|
|
@@ -304,7 +337,9 @@ module Updater
|
|
304
337
|
|
305
338
|
private
|
306
339
|
def signal_worker
|
307
|
-
if @
|
340
|
+
if @socket
|
341
|
+
@socket.write '.'
|
342
|
+
elsif @pid
|
308
343
|
Process::kill "USR2", @pid
|
309
344
|
end
|
310
345
|
end
|
data/spec/named_request_spec.rb
CHANGED
@@ -8,29 +8,49 @@ describe "named request" do
|
|
8
8
|
|
9
9
|
before(:each) do
|
10
10
|
Foo.all.destroy!
|
11
|
+
Update.clear_all
|
11
12
|
end
|
12
13
|
|
13
14
|
it "should be found by name when target is an instance" do
|
14
15
|
f = Foo.create(:name=>'Honey')
|
15
16
|
u = Update.immidiate(f,:bar,[:named],:name=>'Now')
|
16
17
|
u.name.should ==("Now")
|
17
|
-
pending "'for' not implemented"
|
18
18
|
Update.for(f, "Now").should ==(u)
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should be found by name when target is a class" do
|
22
22
|
u = Update.immidiate(Foo,:bar,[:named],:name=>'Now')
|
23
23
|
u.name.should ==("Now")
|
24
|
-
pending "'for' not implemented"
|
25
24
|
Update.for(Foo, "Now").should ==(u)
|
26
25
|
end
|
27
26
|
|
28
27
|
it "should return all updates for a given target" do
|
29
|
-
u1 = Update.immidiate(Foo,:bar,[:arg1,:arg2])
|
28
|
+
u1 = Update.immidiate(Foo,:bar,[:arg1,:arg2], :name=>'First')
|
30
29
|
u2 = Update.immidiate(Foo,:bar,[:arg3,:arg4])
|
31
|
-
pending "'for' not implemented"
|
32
30
|
Update.for(Foo).should include(u1,u2)
|
33
31
|
end
|
34
|
-
|
32
|
+
|
33
|
+
#locked updates are already running and can therefore not be modified
|
34
|
+
it "should not include locked updates" do
|
35
|
+
u = Update.immidiate(Foo,:bar,[:named],:name=>'Now')
|
36
|
+
u.orm.lock(Struct.new(:name).new('test_worker'))
|
37
|
+
u.orm.should be_locked
|
38
|
+
Update.for(Foo).should_not include(u)
|
39
|
+
Update.for(Foo).should be_empty
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should not return rusults with the wrong name" do
|
43
|
+
u = Update.immidiate(Foo,:bar,[:named],:name=>'Now')
|
44
|
+
u.name.should ==("Now")
|
45
|
+
Update.for(Foo, "Then").should be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should not return results for the wring target" do
|
49
|
+
f = Foo.create(:name=>'Honey')
|
50
|
+
g = Foo.create(:name=>'Sweetie Pie')
|
51
|
+
u = Update.immidiate(f,:bar,[:named],:name=>'Now')
|
52
|
+
Update.for(f).should include(u)
|
53
|
+
Update.for(g).should be_empty
|
54
|
+
end
|
35
55
|
|
36
56
|
end
|
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.
|
4
|
+
version: 0.9.0
|
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: 2010-
|
12
|
+
date: 2010-03-26 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|