updater 0.9.3.2 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.3.2
1
+ 0.9.4
@@ -73,6 +73,7 @@ module Updater
73
73
  stop(false)
74
74
  false
75
75
  when :USR2, :DATA #wake up a child and get to work
76
+ logger.info {"Master Process recieved job ready signal"}
76
77
  @pipe.last.write_nonblock('.')
77
78
  true
78
79
  when :TTIN
@@ -142,7 +143,7 @@ module Updater
142
143
  timeout = calc_timeout
143
144
  logger.debug { "Sleeping for #{timeout}" }
144
145
  ready, _1, _2 = IO.select(@wakeup_set, nil, nil, timeout)
145
- return unless ready && ready.first #timeout hit, just wakeup and run maintance
146
+ return unless ready && ready.first #timeout hit or self_pipe alerted, just wakeup and run maintance
146
147
  add_connection(ready.first) and return if ready.first.respond_to?(:accept) #open a new incomming connection
147
148
  @signal_queue << :DATA unless ready.first == @self_pipe.first
148
149
  loop {ready.first.read_nonblock(16 * 1024)}
@@ -32,7 +32,7 @@ module Updater
32
32
  end
33
33
 
34
34
  def _id=(val)
35
- val = BSON::ObjectID.from_string(val.to_s) unless val.kind_of? BSON::ObjectID
35
+ val = BSON::ObjectId.from_string(val.to_s) unless val.kind_of? BSON::ObjectId
36
36
  @hash[:_id] = val
37
37
  end
38
38
 
@@ -59,7 +59,7 @@ module Updater
59
59
  job
60
60
  end
61
61
  end
62
- _id = self.class.collection.save @hash
62
+ _id = self.class.collection.save(@hash, :safe=>true)
63
63
  end
64
64
 
65
65
  def destroy
@@ -106,10 +106,10 @@ module Updater
106
106
 
107
107
  private
108
108
  # this method is calld from he chain asignment methods eg. failure=(chain)
109
- # chain is an array which may contain BSON::ObjectID's or Updater::Update's or both
110
- # For BSON::ObjectID's we cannot initialize them as this could leed to infinate loops.
109
+ # chain is an array which may contain BSON::ObjectId's or Updater::Update's or both
110
+ # For BSON::ObjectId's we cannot initialize them as this could leed to infinate loops.
111
111
  # (an object pool would solve this problem, but feels like overkill)
112
- # The final result must be a @hash containing all the BSON::ObjectID' (forign keys)
112
+ # The final result must be a @hash containing all the BSON::ObjectId' (forign keys)
113
113
  # and possibly @failure containting all instanciated UpdaterUpdates read to be called
114
114
  # or @failure set to nil with the chain instanciated on first use.
115
115
  def build_chain_arrays(arr, build = false)
@@ -131,20 +131,20 @@ module Updater
131
131
  [nil,output[:ids]]
132
132
  end
133
133
 
134
- # This method takes something that may be a reference to an instance(BSON::ObjectID/String),
134
+ # This method takes something that may be a reference to an instance(BSON::ObjectId/String),
135
135
  # an instance its self (Updater::Update), or a Hash
136
- # and returns a touple of the Updater::Update,BSON::ObjectID.
137
- # This method will bot instanciate object from BSON::ObjectID's
136
+ # and returns a touple of the Updater::Update,BSON::ObjectId.
137
+ # This method will bot instanciate object from BSON::ObjectId's
138
138
  # nor will it save Hashes inorder to obtain an ID (it will creat a new Updater::Update from the hash).
139
139
  # Instead it will return nil in the appropriate place.
140
140
  def rationalize_instance(val)
141
- val = BSON::ObjectID.fron_string(val) if val.kind_of? String
142
- case val #aval is the actual runable object, hval is a BSON::ObjectID that we can put into the Database
141
+ val = BSON::ObjectId.fron_string(val) if val.kind_of? String
142
+ case val #aval is the actual runable object, hval is a BSON::ObjectId that we can put into the Database
143
143
  when Updater::Update
144
144
  val.params ? [val,[val.id,val.params]] : [val,val.id]
145
145
  when Hash
146
146
  [Updater::Update.new(val),val['_id']]
147
- when BSON::ObjectID
147
+ when BSON::ObjectId
148
148
  [nil,val]
149
149
  when Array
150
150
  rationalize_instance(val[0]).tap do |ret|
@@ -227,7 +227,7 @@ module Updater
227
227
  end
228
228
 
229
229
  def get(id)
230
- id = BSON::ObjectID.from_string(id) if id.kind_of? String
230
+ id = BSON::ObjectId.from_string(id) if id.kind_of? String
231
231
  new(@collection.find_one(id))
232
232
  end
233
233
 
@@ -249,6 +249,7 @@ module Updater
249
249
 
250
250
  def queue_time
251
251
  nxt = @collection.find_one({:lock_name=>nil, :time=>{'$ne'=>nil}}, :sort=>[[:time, :asc]], :fields=>[:time])
252
+ # logger.debug {" the queue is empty"} unless nxt
252
253
  return nil unless nxt
253
254
  return 0 if nxt['time'] <= tnow
254
255
  return nxt['time'] - tnow
@@ -267,6 +268,14 @@ module Updater
267
268
  @collection.update({:lock_name=>worker.name},{'$unset'=>{:lock_name=>1}},:multi=>true)
268
269
  end
269
270
 
271
+ def for(target,finder,args,name)
272
+ if name
273
+ @collection.find(:target=>target.to_s, :finder_args=>args,:name=>name)
274
+ else
275
+ @collection.find(:target=>target.to_s, :finder_args=>args)
276
+ end
277
+ end
278
+
270
279
  private
271
280
  def tnow
272
281
  Updater::Update.time.now.to_i
data/lib/updater/setup.rb CHANGED
@@ -6,26 +6,33 @@ require 'erb'
6
6
  module Updater
7
7
  class Setup
8
8
  class << self
9
+ #start a new server
9
10
  def start(options={})
10
11
  new(config_file(options), options).start
11
12
  end
12
13
 
14
+ #stop the server
13
15
  def stop(options={})
14
16
  new(config_file(options), options).stop
15
17
  end
16
18
 
19
+ # Used for testing. Will run through the entire setup process, but
20
+ # not actually start the server, but will log the resulting options.
17
21
  def noop(options={})
18
22
  new(config_file(options), options).noop
19
23
  end
20
24
 
25
+ # Connect a client to a server
21
26
  def client_setup(options = {})
22
27
  new(config_file(options), options).client_setup
23
28
  end
24
29
 
30
+ # pendeing
25
31
  def monitor
26
32
 
27
33
  end
28
-
34
+
35
+ # Retruns tha locaion of the config file.
29
36
  def config_file(options = {})
30
37
  if options[:config_file] && File.exists?(options[:config_file])
31
38
  options[:config_file]
@@ -48,7 +55,7 @@ module Updater
48
55
  @logger = @options[:logger] || Logger.new(@options[:log_file] || STDOUT)
49
56
  level = Logger::SEV_LABEL.index(@options[:log_level].upcase) if @options[:log_level]
50
57
  @logger.level = level || Logger::WARN unless @options[:logger] #only set this if we were not handed a logger
51
- @logger.debug "Debugging output enabled"
58
+ @logger.debug "Debugging output enabled" unless @options[:logger]
52
59
  Update.logger = @logger
53
60
  end
54
61
 
@@ -80,25 +87,45 @@ module Updater
80
87
  @logger.info "Updater Client is being initialized..."
81
88
  set_orm
82
89
 
83
- if @options[:socket] && File.exists?(@options[:socket])
84
- @logger.debug "Using UNIX Socket \"#{@options[:socket]}\""
85
- Updater::Update.socket = UNIXSocket.new(@options[:socket])
86
- elsif @options[:udp]
87
- socket = UDPSocket.new()
88
- socket.connect(@options[:host],@options[:udp])
89
- Updater::Update.socket = socket
90
- elsif @options[:tcp]
91
- Updater::Update.socket = TCPSocket.new(@options[:host],@options[:tcp])
92
- elsif @options[:remote]
93
- raise NotImplimentedError #For future Authenticated Http Rest Server
94
- end
90
+ Updater::Update.socket = socket_for_client
91
+
92
+
93
+ init_orm
95
94
 
96
95
  #set PID
97
96
  if File.exists? @options[:pid_file]
98
97
  Updater::Update.pid = File.read(@options[:pid_file]).strip
99
98
  end
100
99
 
101
-
100
+ Updater::Update.config_file = @config_file
101
+ self
102
+ end
103
+
104
+ def socket_for_client
105
+ if @options[:socket] && File.exists?(@options[:socket])
106
+ @logger.debug "Using UNIX Socket \"#{@options[:socket]}\""
107
+ return UNIXSocket.new(@options[:socket]) if File.exists?(@options[:socket]) && File.stat(@options[:socket]).socket?
108
+ end
109
+ if @options[:udp]
110
+ socket = UDPSocket.new()
111
+ socket.connect(@options[:host],@options[:udp])
112
+ begin
113
+ socket.write '.' #must test UDP sockets
114
+ return socket
115
+ rescue Errno::ECONNREFUSED
116
+ end
117
+ end
118
+ if @options[:tcp]
119
+ begin
120
+ return TCPSocket.new(@options[:host],@options[:tcp])
121
+ rescue Errno::ECONNREFUSED
122
+ end
123
+ end
124
+ if @options[:remote]
125
+ return nil
126
+ raise NotImplimentedError #For future Authenticated Http Rest Server
127
+ end
128
+ return nil
102
129
  end
103
130
 
104
131
  private
@@ -212,6 +212,8 @@ module Updater
212
212
  if inst
213
213
  worker.logger.debug " running job #{inst.id}"
214
214
  new(inst).run
215
+ else
216
+ worker.logger.debug " could not find a ready job in the datastore"
215
217
  end
216
218
  @orm.queue_time
217
219
  ensure
@@ -405,6 +407,9 @@ module Updater
405
407
  @orm.clear_all
406
408
  end
407
409
 
410
+ # The name of the file to look for information if we loose the server
411
+ attr_accessor :config_file
412
+
408
413
  #Sets the process id of the worker process if known. If this
409
414
  #is set then an attempt will be made to signal the worker any
410
415
  #time a new update is made.
@@ -431,12 +436,46 @@ module Updater
431
436
 
432
437
  private
433
438
  def signal_worker
434
- # TODO: If worker process goes down or has to be reset, try to reconnect
435
- if @socket
436
- @socket.write '.'
437
- elsif @pid
438
- Process::kill "USR2", @pid
439
+ errored = false
440
+ begin
441
+ if @socket
442
+ @socket.write '.'
443
+ logger.debug "Signaled Master Process Via Socket"
444
+ elsif @pid
445
+ Process::kill "USR2", @pid
446
+ logger.debug "Signaled Master Process Via PID"
447
+ else
448
+ signal_worker if connection_refresh
449
+ end
450
+ rescue SystemCallError
451
+ logger.warn "Lost Client Connection to Updater Server"
452
+ if connection_refresh && !errored
453
+ errored = true
454
+ retry
455
+ end
456
+ end
457
+ end
458
+
459
+ def connection_refresh
460
+ logger.debug "Connection Refresh Attempted"
461
+ @socket.close if @socket
462
+ @socket = nil; @pid = nil #assume the old server died
463
+ @connection_refresh ||= [1,Time.now-1]
464
+ delay, time = @connection_refresh
465
+ if Time.now >= time+delay
466
+ Setup.new(@config_file, :logger=>logger).client_setup
467
+ if @pid || @socket #assume we were successful and retry
468
+ @connection_refresh = nil
469
+ return true
470
+ else
471
+ logger.debug "Connection Refresh Failed"
472
+ #we are still not able to connect, don't try again for a while
473
+ @connection_refresh= [[delay*2,10*60].min,Time.now]
474
+ return false
475
+ end
439
476
  end
477
+ logger.debug "Connection Refresh Waiting until #{time+delay}"
478
+ return false
440
479
  end
441
480
 
442
481
  # Given some instance return the information needed to recreate that target
data/lib/updater.rb CHANGED
@@ -4,4 +4,5 @@ module Updater
4
4
  VERSION = File.read(File.join(File.dirname(__FILE__),'..','VERSION')).strip
5
5
  end
6
6
 
7
- require 'updater/update.rb'
7
+ require 'updater/update.rb'
8
+ require 'updater/setup.rb'
data/spec/spec_helper.rb CHANGED
@@ -8,7 +8,7 @@ require "dm-core"
8
8
  require 'dm-migrations'
9
9
 
10
10
  require 'updater'
11
- #require 'updater/thread_worker'
11
+ require 'updater/thread_worker'
12
12
  require 'updater/fork_worker'
13
13
  require 'updater/orm/datamapper'
14
14
 
data/spec/update_spec.rb CHANGED
@@ -13,7 +13,7 @@ describe Update do
13
13
 
14
14
  end
15
15
 
16
- context "Gemspec: " do
16
+ describe "Gemspec: " do
17
17
  it"should match version" do
18
18
  gs = File.open(File.join(ROOT,'updater.gemspec')) do |f|
19
19
  eval f.read
metadata CHANGED
@@ -5,9 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 9
8
- - 3
9
- - 2
10
- version: 0.9.3.2
8
+ - 4
9
+ version: 0.9.4
11
10
  platform: ruby
12
11
  authors:
13
12
  - John F. Miller
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-08-26 00:00:00 -07:00
17
+ date: 2011-02-14 00:00:00 -08:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency