bluth 0.7.0 → 0.7.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.
@@ -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