bluth 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +13 -0
- data/Rakefile +2 -1
- data/VERSION.yml +2 -2
- data/bin/bluth +99 -0
- data/bluth.gemspec +19 -6
- data/lib/bluth/cli.rb +72 -0
- data/lib/bluth/gob.rb +0 -179
- data/lib/bluth/test_helpers.rb +33 -0
- data/lib/bluth/worker.rb +104 -135
- data/lib/bluth.rb +217 -129
- data/try/15_queue_try.rb +30 -0
- data/try/16_worker_try.rb +23 -0
- data/try/17_gob_try.rb +49 -0
- data/try/18_handler_try.rb +0 -0
- data/try/19_bluth_try.rb +41 -0
- metadata +33 -11
data/lib/bluth/worker.rb
CHANGED
@@ -1,7 +1,21 @@
|
|
1
|
+
require 'benchmark'
|
1
2
|
require 'eventmachine'
|
2
3
|
require 'rufus/scheduler'
|
3
4
|
require 'daemonizing'
|
4
|
-
|
5
|
+
|
6
|
+
class Rufus::Scheduler::SchedulerCore
|
7
|
+
# See lib/rufus/sc/scheduler.rb
|
8
|
+
def handle_exception(task, exception)
|
9
|
+
case exception
|
10
|
+
when SystemExit
|
11
|
+
exit
|
12
|
+
else
|
13
|
+
Familia.info exception.message
|
14
|
+
Familia.info exception.backtrace
|
15
|
+
task.unschedule
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
5
19
|
|
6
20
|
module Bluth
|
7
21
|
@salt = rand.gibbler.shorten(10).freeze
|
@@ -10,30 +24,29 @@ module Bluth
|
|
10
24
|
end
|
11
25
|
|
12
26
|
module WorkerBase
|
13
|
-
|
14
|
-
def
|
15
|
-
@
|
27
|
+
|
28
|
+
def init(h=nil, u=nil, w=nil)
|
29
|
+
@host, @user, @wid, = h || Bluth.sysinfo.hostname, u || Bluth.sysinfo.user, w
|
30
|
+
@pid_file ||= "/tmp/#{self.class.prefix}-#{wid}.pid"
|
31
|
+
@log_file ||= "/tmp/#{self.class.prefix}-#{wid}.log"
|
32
|
+
@success ||= 0
|
33
|
+
@failure ||= 0
|
34
|
+
@problem ||= 0
|
16
35
|
end
|
17
36
|
|
18
|
-
def
|
19
|
-
[host, user,
|
37
|
+
def wid
|
38
|
+
@wid ||= [host, user, rand, Time.now.to_f].gibbler.short
|
39
|
+
@wid
|
20
40
|
end
|
21
41
|
|
22
42
|
# Used by daemonize as the process name (linux only)
|
23
43
|
def name
|
24
|
-
"
|
44
|
+
"bluth-#{self.class.prefix}-#{wid}"
|
25
45
|
end
|
26
46
|
|
27
|
-
def
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
def initialize
|
32
|
-
@host, @user = Bluth.sysinfo.hostname, Bluth.sysinfo.user
|
33
|
-
@pid_file ||= "/tmp/#{self.class.prefix}-#{id}.pid"
|
34
|
-
@log_file ||= "/tmp/#{self.class.prefix}-#{id}.log"
|
35
|
-
@success, @failure, @problem = 0, 0, 0
|
36
|
-
end
|
47
|
+
#def rediskey(suffix=nil)
|
48
|
+
# self.class.rediskey index, suffix
|
49
|
+
#end
|
37
50
|
|
38
51
|
def current_job
|
39
52
|
Gibbler::Digest.new(@current_job || '')
|
@@ -41,12 +54,12 @@ module Bluth
|
|
41
54
|
|
42
55
|
def kill(force=false)
|
43
56
|
if force || host == Bluth.sysinfo.hostname
|
44
|
-
|
57
|
+
Familia.info "Destroying #{self.index} (this machine is: #{Bluth.sysinfo.hostname}; worker is: #{host})"
|
45
58
|
Worker.kill self.pid_file if File.exists?(self.pid_file) rescue Errno::ESRCH
|
46
59
|
File.delete self.log_file if File.exists?(self.log_file)
|
47
60
|
destroy!
|
48
61
|
else
|
49
|
-
|
62
|
+
Familia.info "Worker #{self.index} not running on #{Bluth.sysinfo.hostname}"
|
50
63
|
end
|
51
64
|
end
|
52
65
|
|
@@ -62,49 +75,57 @@ module Bluth
|
|
62
75
|
|
63
76
|
module ClassMethods
|
64
77
|
def from_redis(wid)
|
65
|
-
me = new
|
66
|
-
me.
|
67
|
-
super(me.longid)
|
78
|
+
me = new nil, nil, wid
|
79
|
+
super(me.index)
|
68
80
|
end
|
69
|
-
|
70
81
|
def run!(*args)
|
71
82
|
me = new
|
72
|
-
Familia.info "Created: #{me.
|
83
|
+
Familia.info "Created: #{me.rediskey}"
|
73
84
|
me.run!
|
74
85
|
me
|
75
86
|
end
|
76
|
-
|
77
87
|
def run(*args)
|
78
88
|
me = new
|
79
|
-
Familia.info "Created: #{me.
|
89
|
+
Familia.info "Created: #{me.rediskey}"
|
80
90
|
me.run
|
81
91
|
me
|
82
92
|
end
|
83
|
-
|
84
93
|
def kill(pid_file)
|
94
|
+
self.class.runblock :onexit
|
85
95
|
pid = read_pid_file pid_file
|
86
96
|
super(pid_file, 10)
|
87
97
|
end
|
88
|
-
|
89
|
-
|
98
|
+
def onstart &blk
|
99
|
+
@onstart = blk unless blk.nil?
|
100
|
+
@onstart
|
101
|
+
end
|
102
|
+
def onexit &blk
|
103
|
+
@onexit = blk unless blk.nil?
|
104
|
+
@onexit
|
105
|
+
end
|
106
|
+
# A convenience method for calling onstart/onexit blocks
|
107
|
+
def runblock meth
|
108
|
+
blk = self.send(meth)
|
109
|
+
return if blk.nil?
|
110
|
+
instance_eval &blk
|
111
|
+
end
|
90
112
|
end
|
91
|
-
|
92
113
|
end
|
93
114
|
|
94
115
|
class Worker < Storable
|
95
|
-
|
96
|
-
@interval = 2.seconds
|
116
|
+
@interval = 2 #.seconds
|
97
117
|
class << self
|
98
118
|
attr_accessor :interval
|
99
119
|
end
|
120
|
+
include WorkerBase
|
100
121
|
include Familia
|
101
122
|
include Logging
|
102
123
|
include Daemonizable
|
103
124
|
prefix :worker
|
104
|
-
index :
|
125
|
+
index [:host, :user, :wid]
|
105
126
|
field :host
|
106
127
|
field :user
|
107
|
-
field :
|
128
|
+
field :wid
|
108
129
|
field :process_id => Integer
|
109
130
|
field :pid_file
|
110
131
|
field :log_file
|
@@ -113,35 +134,28 @@ module Bluth
|
|
113
134
|
field :failure => Integer
|
114
135
|
field :problem => Integer
|
115
136
|
include Familia::Stamps
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
@failure += 1
|
124
|
-
@current_job = ""
|
125
|
-
update_time
|
126
|
-
save
|
127
|
-
end
|
128
|
-
def problem!
|
129
|
-
@problem += 1
|
130
|
-
@current_job = ""
|
131
|
-
update_time
|
132
|
-
save
|
137
|
+
[:success, :failure, :problem].each do |name|
|
138
|
+
define_method "#{name}!" do
|
139
|
+
v = self.send(name) + 1
|
140
|
+
self.send :"#{name}=", v
|
141
|
+
self.instance_variable_set '@current_job', ''
|
142
|
+
update_time! # calls save
|
143
|
+
end
|
133
144
|
end
|
134
145
|
|
135
146
|
def run!
|
136
147
|
begin
|
148
|
+
self.class.runblock :onstart
|
137
149
|
find_gob
|
138
150
|
rescue => ex
|
139
151
|
msg = "#{ex.class}: #{ex.message}"
|
140
|
-
|
141
|
-
Familia.
|
152
|
+
Familia.info msg
|
153
|
+
Familia.trace :EXCEPTION, msg, caller[1] if Familia.debug?
|
154
|
+
self.class.runblock :onexit
|
142
155
|
destroy!
|
143
156
|
rescue Interrupt => ex
|
144
157
|
puts $/, "Exiting..."
|
158
|
+
self.class.runblock :onexit
|
145
159
|
destroy!
|
146
160
|
end
|
147
161
|
end
|
@@ -150,19 +164,10 @@ module Bluth
|
|
150
164
|
begin
|
151
165
|
@process_id = $$
|
152
166
|
save
|
153
|
-
|
167
|
+
self.class.runblock :onstart
|
154
168
|
scheduler = Rufus::Scheduler.start_new
|
155
169
|
Familia.info "Setting interval: #{Worker.interval} sec (poptimeout: #{Bluth.poptimeout})"
|
156
170
|
Familia.reconnect_all! # Need to reconnect after daemonize
|
157
|
-
## TODO: Works but needs to restart scheduler
|
158
|
-
##Signal.trap("USR1") do
|
159
|
-
## Worker.interval += 1
|
160
|
-
## Familia.info "Setting interval: #{Worker.interval} sec"
|
161
|
-
##end
|
162
|
-
##Signal.trap("USR2") do
|
163
|
-
## Worker.interval -= 1
|
164
|
-
## Familia.info "Setting interval: #{Worker.interval}"
|
165
|
-
##end
|
166
171
|
scheduler.every Worker.interval, :blocking => true do |task|
|
167
172
|
Familia.ld "#{$$} TICK @ #{Time.now.utc}"
|
168
173
|
sleep rand
|
@@ -172,8 +177,9 @@ module Bluth
|
|
172
177
|
|
173
178
|
rescue => ex
|
174
179
|
msg = "#{ex.class}: #{ex.message}"
|
175
|
-
|
176
|
-
Familia.
|
180
|
+
Familia.info msg
|
181
|
+
Familia.trace :EXCEPTION, msg, caller[1] if Familia.debug?
|
182
|
+
self.class.runblock :onexit
|
177
183
|
destroy!
|
178
184
|
rescue Interrupt => ex
|
179
185
|
puts <<-EOS.gsub(/(?:^|\n)\s*/, "\n")
|
@@ -183,6 +189,7 @@ module Bluth
|
|
183
189
|
EOS
|
184
190
|
# We reconnect to the queue in case we're currently
|
185
191
|
# waiting on a brpop (blocking pop) timeout.
|
192
|
+
self.class.runblock :onexit
|
186
193
|
destroy!
|
187
194
|
end
|
188
195
|
|
@@ -190,13 +197,13 @@ module Bluth
|
|
190
197
|
|
191
198
|
|
192
199
|
private
|
193
|
-
|
200
|
+
|
194
201
|
# DO NOT return from this method
|
195
202
|
def find_gob(task=nil)
|
196
203
|
begin
|
197
204
|
job = Bluth.pop
|
198
205
|
unless job.nil?
|
199
|
-
job.wid = self.
|
206
|
+
job.wid = self.wid
|
200
207
|
if job.delayed?
|
201
208
|
job.attempts = 0
|
202
209
|
job.retry!
|
@@ -204,7 +211,7 @@ module Bluth
|
|
204
211
|
job.failure! "Too many attempts"
|
205
212
|
else
|
206
213
|
job.stime = Time.now.utc.to_i
|
207
|
-
self.working! job.
|
214
|
+
self.working! job.jobid
|
208
215
|
tms = Benchmark.measure do
|
209
216
|
job.perform
|
210
217
|
end
|
@@ -243,114 +250,76 @@ module Bluth
|
|
243
250
|
#end
|
244
251
|
end
|
245
252
|
end
|
246
|
-
|
247
253
|
end
|
248
254
|
|
255
|
+
# TODO: Refactor somehow. When this is subclassed
|
256
|
+
# (eg BS::SchduleWorker) the self.object is not created.
|
249
257
|
class ScheduleWorker < Storable
|
250
258
|
include WorkerBase
|
259
|
+
include Familia
|
260
|
+
include Logging
|
261
|
+
include Daemonizable
|
251
262
|
@interval = 20
|
252
263
|
@timeout = 60 #not working
|
264
|
+
@every = []
|
253
265
|
class << self
|
254
|
-
attr_accessor :interval, :timeout
|
266
|
+
attr_accessor :interval, :timeout, :schedule
|
255
267
|
def interval(v=nil)
|
256
268
|
@interval = v unless v.nil?
|
257
269
|
@interval
|
258
270
|
end
|
271
|
+
def every interval=nil, opts={}, &blk
|
272
|
+
unless interval.nil?
|
273
|
+
@every << [interval, opts, blk]
|
274
|
+
end
|
275
|
+
@every
|
276
|
+
end
|
259
277
|
end
|
260
|
-
include Familia
|
261
|
-
include Logging
|
262
|
-
include Daemonizable
|
263
278
|
prefix :scheduler
|
264
|
-
index :
|
279
|
+
index [:host, :user, :wid]
|
265
280
|
field :host
|
266
281
|
field :user
|
267
|
-
field :
|
282
|
+
field :wid
|
268
283
|
field :process_id => Integer
|
269
284
|
field :pid_file
|
270
285
|
field :log_file
|
271
|
-
field :scheduled => Integer
|
272
|
-
field :monitored => Integer
|
273
|
-
field :timeouts => Integer
|
274
286
|
include Familia::Stamps
|
275
|
-
|
276
|
-
attr_reader :monitors
|
277
|
-
|
278
|
-
def scheduled!(count=1)
|
279
|
-
@scheduled ||= 0
|
280
|
-
@scheduled += count
|
281
|
-
update_time
|
282
|
-
save
|
283
|
-
end
|
284
|
-
def monitored!(count=1)
|
285
|
-
@monitored ||= 0
|
286
|
-
@monitored += count
|
287
|
-
update_time
|
288
|
-
save
|
289
|
-
end
|
290
|
-
def timeout!(count=1)
|
291
|
-
@timeouts ||= 0
|
292
|
-
@timeouts += count
|
293
|
-
update_time
|
294
|
-
save
|
295
|
-
end
|
287
|
+
|
296
288
|
def run!
|
297
289
|
run
|
298
290
|
end
|
291
|
+
|
299
292
|
def run
|
300
293
|
begin
|
301
|
-
raise Familia::Problem, "Only 1 scheduler at a time" if ScheduleWorker.
|
302
|
-
|
294
|
+
raise Familia::Problem, "Only 1 scheduler at a time" if !ScheduleWorker.instances.empty?
|
303
295
|
EM.run {
|
304
296
|
@process_id = $$
|
305
297
|
srand(Bluth.salt.to_i(16) ** @process_id)
|
306
|
-
|
298
|
+
ScheduleWorker.schedule = Rufus::Scheduler::EmScheduler.start_new
|
307
299
|
save # persist and make note the scheduler is running
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
msg = "#{ex.class}: #{ex.message}"
|
314
|
-
STDERR.puts msg
|
315
|
-
STDERR.puts ex.backtrace
|
316
|
-
Familia.ld :EXCEPTION, msg, caller[1] if Familia.debug?
|
317
|
-
end
|
318
|
-
sleep rand # prevent thrashing
|
300
|
+
self.class.runblock :onstart
|
301
|
+
self.class.every.each do |args|
|
302
|
+
interval, opts, blk = *args
|
303
|
+
Familia.ld " scheduling every #{interval}: #{opts}"
|
304
|
+
ScheduleWorker.schedule.every interval, opts, &blk
|
319
305
|
end
|
320
306
|
}
|
321
307
|
rescue => ex
|
322
308
|
msg = "#{ex.class}: #{ex.message}"
|
323
309
|
puts msg
|
324
|
-
|
325
|
-
Familia.
|
310
|
+
Familia.info ex.backtrace
|
311
|
+
Familia.trace :EXCEPTION, msg, caller[1] if Familia.debug?
|
312
|
+
self.class.runblock :onexit
|
326
313
|
destroy!
|
327
314
|
rescue Interrupt => ex
|
328
315
|
puts $/, "Exiting..."
|
316
|
+
self.class.runblock :onexit
|
329
317
|
destroy!
|
330
318
|
end
|
331
319
|
end
|
332
320
|
|
333
|
-
protected
|
334
|
-
|
335
|
-
def prepare
|
336
|
-
end
|
337
|
-
|
338
|
-
def scheduled_work(keeper)
|
339
|
-
STDOUT.puts "Come on!"
|
340
|
-
end
|
341
|
-
|
342
321
|
end
|
343
322
|
|
323
|
+
Bluth.scheduler = Bluth::ScheduleWorker
|
344
324
|
end
|
345
325
|
|
346
|
-
class Rufus::Scheduler::SchedulerCore
|
347
|
-
# See lib/rufus/sc/scheduler.rb
|
348
|
-
def handle_exception(job, exception)
|
349
|
-
case exception
|
350
|
-
when SystemExit
|
351
|
-
exit
|
352
|
-
else
|
353
|
-
super
|
354
|
-
end
|
355
|
-
end
|
356
|
-
end
|