bluth 0.5.3 → 0.6.0
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.
- 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
|