updater 0.3.2 → 0.9.0
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/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
|