bluth 0.7.0 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +20 -0
- data/Rakefile +1 -1
- data/VERSION.yml +1 -1
- data/bin/bluth +2 -0
- data/bluth.gemspec +5 -5
- data/lib/bluth.rb +18 -2
- data/lib/bluth/cli.rb +14 -7
- data/lib/bluth/timingbelt.rb +7 -6
- data/lib/bluth/worker.rb +85 -36
- data/try/30_timingbelt_try.rb +2 -3
- metadata +3 -3
data/CHANGES.txt
CHANGED
@@ -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.
|
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
|
|
data/VERSION.yml
CHANGED
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
|
data/bluth.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{bluth}
|
8
|
-
s.version = "0.7.
|
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-
|
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.
|
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.
|
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.
|
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
|
data/lib/bluth.rb
CHANGED
@@ -35,7 +35,7 @@ module Bluth
|
|
35
35
|
class Shutdown < Familia::Problem; end
|
36
36
|
@db = 0
|
37
37
|
@env = :dev
|
38
|
-
@queuetimeout =
|
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
|
274
|
+
ttl 60*60*2 # 2 hours
|
259
275
|
index :jobid
|
260
276
|
field :jobid => Gibbler::Digest
|
261
277
|
field :handler => String
|
data/lib/bluth/cli.rb
CHANGED
@@ -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.
|
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
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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 &:
|
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.
|
83
|
+
Familia.info "Killing #{worker.index}"
|
77
84
|
worker.kill @option.force
|
78
85
|
end
|
79
86
|
end
|
data/lib/bluth/timingbelt.rb
CHANGED
@@ -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[
|
71
|
-
@notchcache[
|
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[
|
76
|
-
@notchcache[
|
77
|
-
@notchcache[
|
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[
|
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) }
|
data/lib/bluth/worker.rb
CHANGED
@@ -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.
|
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.
|
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 =
|
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
|
-
|
151
|
-
|
152
|
-
|
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
|
-
|
174
|
-
Familia.
|
175
|
-
|
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
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
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
|
-
|
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
|
|
data/try/30_timingbelt_try.rb
CHANGED
@@ -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.
|
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-
|
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.
|
24
|
+
version: 0.7.1
|
25
25
|
type: :runtime
|
26
26
|
version_requirements: *id001
|
27
27
|
- !ruby/object:Gem::Dependency
|