bluth 0.7.0 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,25 @@
1
1
  BLUTH, CHANGES
2
2
 
3
+ #### 0.7.2 (2011-04-10) ###############################
4
+
5
+ * FIXED: Bluth::TimingBelt.notch now caches notches by absolute time (not just HH:MM)
6
+ * CHANGE: Gracefully rescue Errno::ECONNREFUSED and try to reconnect
7
+ * ADDED: Bluth::Worker.reconnect!
8
+ * ADDED: Bluth::Worker.onerror
9
+
10
+
11
+ #### 0.7.1 (2011-03-06) ###############################
12
+
13
+ * FIXED: replace-worker command now always grabs the oldest worker
14
+ and gracefully exits when there's no workers.
15
+ * CHANGE: Bluth::Gob objects have a ttl of 2 hours (up from 1)
16
+ * CHANGE: Bluth::Worker.interval is now 1 sec (down from 2)
17
+ * CHANGE: Default queuetimeout is now 30 seconds (down from 30)
18
+ * ADDED: Bluth::Worker processes now handle USR1 and USR2 signals
19
+ for enabling/disabling debugging and increasing/decreasing
20
+ Bluth.queuetimeout (respectively)
21
+
22
+
3
23
  #### 0.7.0 (2011-03-04) ###############################
4
24
 
5
25
  * ADDED: backtrace field to Bluth::Gob
data/Rakefile CHANGED
@@ -25,7 +25,7 @@ begin
25
25
  gem.email = "delano@solutious.com"
26
26
  gem.homepage = "http://github.com/delano/bluth"
27
27
  gem.authors = ["Delano Mandelbaum"]
28
- gem.add_dependency("familia", ">= 0.6.5")
28
+ gem.add_dependency("familia", ">= 0.7.1")
29
29
  gem.add_dependency('sysinfo', '>= 0.7.3')
30
30
  gem.add_dependency('annoy')
31
31
 
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :MAJOR: 0
3
3
  :MINOR: 7
4
- :PATCH: 0
4
+ :PATCH: 2
data/bin/bluth CHANGED
@@ -66,6 +66,7 @@ class Bluth::CLI::Definition
66
66
 
67
67
  #TODO: command :enqueue
68
68
 
69
+ #option :o, :ontheminute, "Start the worker precisely on the minute"
69
70
  command :start_worker => Bluth::CLI
70
71
  command :start_scheduler => Bluth::CLI
71
72
 
@@ -77,6 +78,7 @@ class Bluth::CLI::Definition
77
78
  command :stop_scheduler => Bluth::CLI
78
79
 
79
80
  about "Stop the oldest worker and start a new instance in its place."
81
+ #option :o, :ontheminute, "Start the worker precisely on the minute"
80
82
  command :replace_worker => Bluth::CLI
81
83
 
82
84
  command :workers => Bluth::CLI
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{bluth}
8
- s.version = "0.7.0"
8
+ s.version = "0.7.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Delano Mandelbaum"]
12
- s.date = %q{2011-03-04}
12
+ s.date = %q{2011-04-12}
13
13
  s.default_executable = %q{bluth}
14
14
  s.description = %q{A Redis queuing system built on top of Familia}
15
15
  s.email = %q{delano@solutious.com}
@@ -50,16 +50,16 @@ Gem::Specification.new do |s|
50
50
  s.specification_version = 3
51
51
 
52
52
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
53
- s.add_runtime_dependency(%q<familia>, [">= 0.6.5"])
53
+ s.add_runtime_dependency(%q<familia>, [">= 0.7.1"])
54
54
  s.add_runtime_dependency(%q<sysinfo>, [">= 0.7.3"])
55
55
  s.add_runtime_dependency(%q<annoy>, [">= 0"])
56
56
  else
57
- s.add_dependency(%q<familia>, [">= 0.6.5"])
57
+ s.add_dependency(%q<familia>, [">= 0.7.1"])
58
58
  s.add_dependency(%q<sysinfo>, [">= 0.7.3"])
59
59
  s.add_dependency(%q<annoy>, [">= 0"])
60
60
  end
61
61
  else
62
- s.add_dependency(%q<familia>, [">= 0.6.5"])
62
+ s.add_dependency(%q<familia>, [">= 0.7.1"])
63
63
  s.add_dependency(%q<sysinfo>, [">= 0.7.3"])
64
64
  s.add_dependency(%q<annoy>, [">= 0"])
65
65
  end
@@ -35,7 +35,7 @@ module Bluth
35
35
  class Shutdown < Familia::Problem; end
36
36
  @db = 0
37
37
  @env = :dev
38
- @queuetimeout = 60 #.seconds
38
+ @queuetimeout = 30 #.seconds
39
39
  @handlers = []
40
40
  @locks = []
41
41
  @sysinfo = nil
@@ -66,6 +66,18 @@ module Bluth
66
66
  def connect
67
67
  instance_eval &onconnect unless onconnect.nil?
68
68
  end
69
+ def reconnect! delay=5
70
+ sleep delay
71
+ success = begin
72
+ Familia.reconnect_all!
73
+ (Bluth::Gob.redis.ping.to_s.upcase == 'PONG')
74
+ rescue => ex
75
+ Familia.info " #{ex.message}"
76
+ false
77
+ end
78
+ Familia.info " reconnected: #{success}"
79
+ success
80
+ end
69
81
  end
70
82
 
71
83
  def Bluth.clear_locks
@@ -173,6 +185,10 @@ module Bluth
173
185
  gob.current_queue = :running
174
186
  gob.save
175
187
  end
188
+
189
+ rescue Errno::ECONNREFUSED => ex
190
+ raise ex
191
+
176
192
  rescue => ex
177
193
  if queue.nil?
178
194
  Familia.info "ERROR: #{ex.message}"
@@ -255,7 +271,7 @@ module Bluth
255
271
  MAX_ATTEMPTS = 3.freeze unless defined?(Gob::MAX_ATTEMPTS)
256
272
  include Familia
257
273
  prefix [:bluth, :gob]
258
- ttl 3600 #.seconds
274
+ ttl 60*60*2 # 2 hours
259
275
  index :jobid
260
276
  field :jobid => Gibbler::Digest
261
277
  field :handler => String
@@ -29,7 +29,7 @@ module Bluth
29
29
  def start_worker worker_class=Bluth::Worker
30
30
  if @global.daemon
31
31
  worker = worker_class.new
32
- Familia.info "Created: #{worker.rediskey}"
32
+ Familia.info "Created: #{worker.index}"
33
33
  worker.daemonize
34
34
  worker.run
35
35
  else
@@ -56,14 +56,21 @@ module Bluth
56
56
 
57
57
  def replace_worker worker_class=Bluth::Worker
58
58
  Bluth.connect
59
- @global.daemon = true
60
- worker = worker_class.instances.first # grabs the oldest worker
61
- kill_worker worker, worker_class
62
- start_worker worker_class
59
+ workers = worker_class.instances.members.select { |w| w.host == Bluth.sysinfo.hostname }
60
+ if workers.empty?
61
+ Familia.info "No workers running on #{Bluth.sysinfo.hostname}"
62
+ else
63
+ workers.sort! { |a,b| a.created <=> b.created }
64
+ oldest_worker = workers.first
65
+ Familia.info "Replacing #{oldest_worker.index}/#{oldest_worker.pid} (running since #{Time.at(oldest_worker.created).utc})"
66
+ kill_worker oldest_worker, worker_class
67
+ @global.daemon = true
68
+ start_worker worker_class
69
+ end
63
70
  end
64
71
 
65
72
  def workers worker_class=Bluth::Worker
66
- Familia.info worker_class.all.collect &:rediskey
73
+ Familia.info worker_class.all.collect &:index
67
74
  end
68
75
 
69
76
  private
@@ -73,7 +80,7 @@ module Bluth
73
80
  Familia.info "No such worker"
74
81
  exit 1
75
82
  else
76
- Familia.info "Killing #{worker.rediskey}"
83
+ Familia.info "Killing #{worker.index}"
77
84
  worker.kill @option.force
78
85
  end
79
86
  end
@@ -65,18 +65,19 @@ module Bluth
65
65
  (time + (mins*60)).strftime('%H:%M')
66
66
  end
67
67
  def notch mins=0, filter=nil, time=now
68
+ cache_key = [now(mins, time).to_i, filter].join(':')
68
69
  key = rediskey(stamp(mins, time), filter)
69
70
  @notchcache ||= {}
70
- if @notchcache[key].nil?
71
- @notchcache[key] ||= Familia::Set.new key,
71
+ if @notchcache[cache_key].nil?
72
+ @notchcache[cache_key] ||= Familia::Set.new key,
72
73
  :ttl => 2*60*60, # 2 hours
73
74
  :extend => Bluth::TimingBelt::Notch,
74
75
  :db => Bluth::TimingBelt.db
75
- @notchcache[key].stamp = stamp(mins, time)
76
- @notchcache[key].filter = filter
77
- @notchcache[key].time = now(mins, time)
76
+ @notchcache[cache_key].stamp = stamp(mins, time)
77
+ @notchcache[cache_key].filter = filter
78
+ @notchcache[cache_key].time = now(mins, time)
78
79
  end
79
- @notchcache[key]
80
+ @notchcache[cache_key]
80
81
  end
81
82
  def priority minutes=2, filter=nil, time=now
82
83
  (0..minutes).to_a.reverse.collect { |min| notch(min*-1, filter, time) }
@@ -78,15 +78,27 @@ module Bluth
78
78
  me = new nil, nil, wid
79
79
  super(me.index)
80
80
  end
81
+ def reconnect! name=nil
82
+ Familia.info "Reconnecting #{name}"
83
+ attempt = 0
84
+ success = false
85
+ reconnect_tries.times {
86
+ attempt += 1
87
+ Familia.info " reconnecting in #{reconnect_delay} (\##{attempt} of #{reconnect_tries})..."
88
+ success = Bluth.reconnect! reconnect_delay
89
+ break if success
90
+ }
91
+ success
92
+ end
81
93
  def run!(*args)
82
94
  me = new
83
- Familia.info "Created: #{me.rediskey}"
95
+ Familia.info "Created: #{me.index}"
84
96
  me.run!
85
97
  me
86
98
  end
87
99
  def run(*args)
88
100
  me = new
89
- Familia.info "Created: #{me.rediskey}"
101
+ Familia.info "Created: #{me.index}"
90
102
  me.run
91
103
  me
92
104
  end
@@ -99,6 +111,10 @@ module Bluth
99
111
  @onstart = blk unless blk.nil?
100
112
  @onstart
101
113
  end
114
+ def onerror &blk
115
+ @onerror = blk unless blk.nil?
116
+ @onerror
117
+ end
102
118
  def onexit &blk
103
119
  @onexit = blk unless blk.nil?
104
120
  @onexit
@@ -113,9 +129,11 @@ module Bluth
113
129
  end
114
130
 
115
131
  class Worker < Storable
116
- @interval = 2 #.seconds
132
+ @interval = 1 #.seconds
133
+ @reconnect_delay = 15 #.seconds
134
+ @reconnect_tries = 20
117
135
  class << self
118
- attr_accessor :interval
136
+ attr_accessor :interval, :reconnect_delay, :reconnect_tries
119
137
  end
120
138
  include WorkerBase
121
139
  include Familia
@@ -143,17 +161,41 @@ module Bluth
143
161
  end
144
162
  end
145
163
 
164
+ def carefully
165
+ begin
166
+ yield
167
+ rescue Errno::ECONNREFUSED => ex
168
+
169
+ unless Bluth::Worker.reconnect! self.index
170
+ self.class.onerror.call ex, self if self.class.onerror
171
+ Familia.info "Reconnect failed :["
172
+ end
173
+
174
+ rescue => ex
175
+ if self.class.onerror
176
+ self.class.onerror.call ex, self
177
+ else
178
+ Familia.info ex.message
179
+ Familia.ld ex.backtrace
180
+ problem!
181
+ end
182
+ #if problem > 5
183
+ # ## TODO: SEND EMAIL
184
+ # task.unschedule unless task.nil? # Kill this worker b/c something is clearly wrong
185
+ # destroy!
186
+ # EM.stop
187
+ # exit 1
188
+ #end
189
+ end
190
+ end
191
+
146
192
  def run!
147
193
  begin
148
194
  Bluth.connect
149
195
  self.class.runblock :onstart
150
- find_gob
151
- rescue => ex
152
- msg = "#{ex.class}: #{ex.message}"
153
- Familia.info msg
154
- Familia.trace :EXCEPTION, msg, caller[1] if Familia.debug?
155
- self.class.runblock :onexit
156
- destroy!
196
+ carefully do
197
+ find_gob
198
+ end
157
199
  rescue Interrupt => ex
158
200
  puts $/, "Exiting..."
159
201
  self.class.runblock :onexit
@@ -164,25 +206,39 @@ module Bluth
164
206
  def run
165
207
  begin
166
208
  @process_id = $$
167
- scheduler = Rufus::Scheduler.start_new
209
+ @scheduler = Rufus::Scheduler.start_new
168
210
  Bluth.connect
169
211
  self.class.runblock :onstart
170
212
  Familia.info "Setting interval: #{Worker.interval} sec (queuetimeout: #{Bluth.queuetimeout})"
171
213
  Familia.reconnect_all! # Need to reconnect after daemonize
172
214
  save
173
- scheduler.every Worker.interval, :blocking => true do |task|
174
- Familia.ld "#{$$} TICK @ #{Time.now.utc}" if Familia.debug?
175
- sleep rand
176
- find_gob task
215
+ Signal.trap("USR1") do
216
+ Familia.debug = (Familia.debug == false)
217
+ Familia.info "Debugging is #{Familia.debug ? 'enabled' : 'disabled'}"
177
218
  end
178
- scheduler.join
179
-
180
- rescue => ex
181
- msg = "#{ex.class}: #{ex.message}"
182
- Familia.info msg
183
- Familia.trace :EXCEPTION, msg, caller[1] if Familia.debug?
184
- self.class.runblock :onexit
185
- destroy!
219
+ @usr2_reduce = true
220
+ Signal.trap("USR2") do
221
+ @usr2_reduce = false if Bluth.queuetimeout <= 2
222
+ @usr2_reduce = true if Bluth.queuetimeout >= 60
223
+ if @usr2_reduce
224
+ #Worker.interval /= 2.0
225
+ Bluth.queuetimeout /= 2
226
+ else
227
+ #Worker.interval *= 2.0
228
+ Bluth.queuetimeout *= 2
229
+ end
230
+ Familia.info "Set intervals: #{Worker.interval} sec / #{Bluth.queuetimeout} sec"
231
+ end
232
+ ## TODO: on_the_minute = Time.at(BS.quantize(Stella.now, 1.minute)+1.minute).utc ## first_at
233
+ ## @option.ontheminute
234
+ @task = @scheduler.every Worker.interval, :blocking => true, :first_in => '2s' do |task|
235
+ carefully do
236
+ Familia.ld "#{$$} TICK @ #{Time.now.utc}" if Familia.debug?
237
+ find_gob task
238
+ end
239
+ end
240
+ @scheduler.join
241
+
186
242
  rescue Interrupt => ex
187
243
  puts <<-EOS.gsub(/(?:^|\n)\s*/, "\n")
188
244
  Exiting...
@@ -191,13 +247,13 @@ module Bluth
191
247
  EOS
192
248
  # We reconnect to the queue in case we're currently
193
249
  # waiting on a brpop (blocking pop) timeout.
194
- self.class.runblock :onexit
195
250
  destroy!
251
+ ensure
252
+ self.class.runblock :onexit
196
253
  end
197
254
 
198
255
  end
199
256
 
200
-
201
257
  private
202
258
 
203
259
  # DO NOT call return from this method
@@ -222,7 +278,7 @@ module Bluth
222
278
  job.success!
223
279
  self.success!
224
280
  end
225
- end
281
+ end
226
282
  rescue Bluth::Shutdown => ex
227
283
  msg = "Shutdown requested: #{ex.message}"
228
284
  job.success! msg
@@ -239,18 +295,11 @@ module Bluth
239
295
  job.failure! ex.message
240
296
  self.failure!
241
297
  rescue => ex
242
- Familia.info ex.message
243
298
  Familia.info ex.backtrace
244
299
  job.retry! "#{ex.class}: #{ex.message}" if job
245
- problem!
246
- #if problem > 5
247
- # ## TODO: SEND EMAIL
248
- # task.unschedule unless task.nil? # Kill this worker b/c something is clearly wrong
249
- # destroy!
250
- # EM.stop
251
- # exit 1
252
- #end
300
+ raise ex
253
301
  end
302
+
254
303
  end
255
304
  end
256
305
 
@@ -9,11 +9,11 @@ Bluth::TimingBelt.redis.flushdb
9
9
 
10
10
  ## Knows now
11
11
  Bluth::TimingBelt.now(0, @now).to_s
12
- #=> '2011-02-14 00:00:00 UTC'
12
+ #=> RUBY_VERSION <= '1.9' ? 'Mon Feb 14 00:00:00 UTC 2011' : '2011-02-14 00:00:00 UTC'
13
13
 
14
14
  ## Now can have an offset
15
15
  Bluth::TimingBelt.now(5, @now).to_s
16
- #=> '2011-02-14 00:05:00 UTC'
16
+ #=> RUBY_VERSION <= '1.9' ? 'Mon Feb 14 00:05:00 UTC 2011' : '2011-02-14 00:05:00 UTC'
17
17
 
18
18
  ## Can create a timestamp
19
19
  Bluth::TimingBelt.stamp 0, @now
@@ -94,7 +94,6 @@ notches.first.name unless notches.first.nil?
94
94
  ## Can calculate the difference between two notches
95
95
  notch1 = Bluth::TimingBelt.notch
96
96
  notch2 = Bluth::TimingBelt.notch 67
97
- puts notch2.name
98
97
  notch2 - notch1
99
98
  #=> 67
100
99
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: bluth
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.7.0
5
+ version: 0.7.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Delano Mandelbaum
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-03-04 00:00:00 -05:00
13
+ date: 2011-04-12 00:00:00 -04:00
14
14
  default_executable: bluth
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -21,7 +21,7 @@ dependencies:
21
21
  requirements:
22
22
  - - ">="
23
23
  - !ruby/object:Gem::Version
24
- version: 0.6.5
24
+ version: 0.7.1
25
25
  type: :runtime
26
26
  version_requirements: *id001
27
27
  - !ruby/object:Gem::Dependency