rq-ruby1.8 3.4.3
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/Gemfile +22 -0
- data/Gemfile.lock +22 -0
- data/INSTALL +166 -0
- data/LICENSE +10 -0
- data/Makefile +6 -0
- data/README +1183 -0
- data/Rakefile +37 -0
- data/TODO +24 -0
- data/TUTORIAL +230 -0
- data/VERSION +1 -0
- data/bin/rq +902 -0
- data/bin/rqmailer +865 -0
- data/example/a.rb +7 -0
- data/extconf.rb +198 -0
- data/gemspec.rb +40 -0
- data/install.rb +210 -0
- data/lib/rq.rb +155 -0
- data/lib/rq/arrayfields.rb +371 -0
- data/lib/rq/backer.rb +31 -0
- data/lib/rq/configfile.rb +82 -0
- data/lib/rq/configurator.rb +40 -0
- data/lib/rq/creator.rb +54 -0
- data/lib/rq/cron.rb +144 -0
- data/lib/rq/defaultconfig.txt +5 -0
- data/lib/rq/deleter.rb +51 -0
- data/lib/rq/executor.rb +40 -0
- data/lib/rq/feeder.rb +527 -0
- data/lib/rq/ioviewer.rb +48 -0
- data/lib/rq/job.rb +51 -0
- data/lib/rq/jobqueue.rb +947 -0
- data/lib/rq/jobrunner.rb +110 -0
- data/lib/rq/jobrunnerdaemon.rb +193 -0
- data/lib/rq/lister.rb +47 -0
- data/lib/rq/locker.rb +43 -0
- data/lib/rq/lockfile.rb +564 -0
- data/lib/rq/logging.rb +124 -0
- data/lib/rq/mainhelper.rb +189 -0
- data/lib/rq/orderedautohash.rb +39 -0
- data/lib/rq/orderedhash.rb +240 -0
- data/lib/rq/qdb.rb +733 -0
- data/lib/rq/querier.rb +98 -0
- data/lib/rq/rails.rb +80 -0
- data/lib/rq/recoverer.rb +28 -0
- data/lib/rq/refresher.rb +80 -0
- data/lib/rq/relayer.rb +283 -0
- data/lib/rq/resource.rb +22 -0
- data/lib/rq/resourcemanager.rb +40 -0
- data/lib/rq/resubmitter.rb +100 -0
- data/lib/rq/rotater.rb +98 -0
- data/lib/rq/sleepcycle.rb +46 -0
- data/lib/rq/snapshotter.rb +40 -0
- data/lib/rq/sqlite.rb +286 -0
- data/lib/rq/statuslister.rb +48 -0
- data/lib/rq/submitter.rb +113 -0
- data/lib/rq/toucher.rb +182 -0
- data/lib/rq/updater.rb +94 -0
- data/lib/rq/usage.rb +1222 -0
- data/lib/rq/util.rb +304 -0
- data/rdoc.sh +17 -0
- data/rq-ruby1.8.gemspec +120 -0
- data/test/.gitignore +1 -0
- data/test/test_rq.rb +145 -0
- data/white_box/crontab +2 -0
- data/white_box/joblist +8 -0
- data/white_box/killrq +18 -0
- data/white_box/rq_killer +27 -0
- metadata +208 -0
data/lib/rq/feeder.rb
ADDED
@@ -0,0 +1,527 @@
|
|
1
|
+
unless defined? $__rq_feeder__
|
2
|
+
module RQ
|
3
|
+
#--{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
require LIBDIR + 'mainhelper'
|
10
|
+
require LIBDIR + 'job'
|
11
|
+
require LIBDIR + 'jobrunner'
|
12
|
+
require LIBDIR + 'jobrunnerdaemon'
|
13
|
+
require LIBDIR + 'jobqueue'
|
14
|
+
|
15
|
+
|
16
|
+
#
|
17
|
+
# TODO - resolve elapsed time bug with throttle/sleep
|
18
|
+
#
|
19
|
+
|
20
|
+
#
|
21
|
+
# the Feeder class is responsible for running jobs from a queue - or
|
22
|
+
# 'feeding' from that queue. the mode of operation is essentially to run
|
23
|
+
# jobs as quickly as possible, return them to the queue, and then to run
|
24
|
+
# more jobs if any exist. if no jobs exist the Feeder will periodically
|
25
|
+
# poll the queue to see if any new jobs have arrived.
|
26
|
+
#
|
27
|
+
class Feeder < MainHelper
|
28
|
+
#--{{{
|
29
|
+
DEFAULT_MIN_SLEEP = 42
|
30
|
+
DEFAULT_MAX_SLEEP = 240
|
31
|
+
DEFAULT_FEED = 2
|
32
|
+
|
33
|
+
class << self
|
34
|
+
#--{{{
|
35
|
+
attr :min_sleep, true
|
36
|
+
attr :max_sleep, true
|
37
|
+
attr :feed, true
|
38
|
+
#--}}}
|
39
|
+
end
|
40
|
+
|
41
|
+
def feed
|
42
|
+
#--{{{
|
43
|
+
daemon do
|
44
|
+
gen_pidfile
|
45
|
+
@main.init_logging
|
46
|
+
@logger = @main.logger
|
47
|
+
set_q
|
48
|
+
|
49
|
+
@pid = Process::pid
|
50
|
+
@cmd = @main.cmd
|
51
|
+
@started = Util::timestamp
|
52
|
+
@min_sleep = Integer(@options['min_sleep'] || defval('min_sleep'))
|
53
|
+
@max_sleep = Integer(@options['max_sleep'] || defval('max_sleep'))
|
54
|
+
@max_feed = Integer(@options['max_feed'] || defval('feed'))
|
55
|
+
@loops = Integer @options['loops'] rescue nil
|
56
|
+
@children = Hash::new
|
57
|
+
@jrd = JobRunnerDaemon::daemon @q
|
58
|
+
|
59
|
+
install_signal_handlers
|
60
|
+
|
61
|
+
if @daemon and not @quiet
|
62
|
+
STDOUT.puts "pid <#{ Process::pid }> started"
|
63
|
+
STDOUT.flush
|
64
|
+
end
|
65
|
+
|
66
|
+
install_redirects
|
67
|
+
|
68
|
+
info{ "** STARTED **" }
|
69
|
+
info{ "version <#{ RQ::VERSION }>" }
|
70
|
+
info{ "cmd <#{ @cmd }>" }
|
71
|
+
info{ "pid <#{ @pid }>" }
|
72
|
+
info{ "pidfile <#{ @pidfile.path }>" }
|
73
|
+
info{ "jobrunnerdaemon uri <#{ @jrd.uri }> pid <#{ @jrd.pid }>" }
|
74
|
+
info{ "qpath <#{ @qpath }>" }
|
75
|
+
debug{ "mode <#{ @mode }>" }
|
76
|
+
debug{ "max_feed <#{ @max_feed }>" }
|
77
|
+
debug{ "min_sleep <#{ @min_sleep }>" }
|
78
|
+
debug{ "max_sleep <#{ @max_sleep }>" }
|
79
|
+
|
80
|
+
transaction do
|
81
|
+
fill_morgue
|
82
|
+
reap_zombie_ios
|
83
|
+
end
|
84
|
+
|
85
|
+
looping do
|
86
|
+
handle_signal if $rq_signaled
|
87
|
+
throttle(@min_sleep) do
|
88
|
+
start_jobs unless busy?
|
89
|
+
if nothing_running?
|
90
|
+
relax
|
91
|
+
else
|
92
|
+
reap_jobs
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
#--}}}
|
98
|
+
end
|
99
|
+
def looping
|
100
|
+
#--{{{
|
101
|
+
@loops && @loops > 0 ? @loops.times{ yield } : loop{ yield }
|
102
|
+
#--}}}
|
103
|
+
end
|
104
|
+
def daemon
|
105
|
+
#--{{{
|
106
|
+
if @options['daemon']
|
107
|
+
fork do
|
108
|
+
Process::setsid
|
109
|
+
pid =
|
110
|
+
fork do
|
111
|
+
Dir::chdir(Util.realpath('~'))
|
112
|
+
File::umask 0
|
113
|
+
@daemon = true
|
114
|
+
yield
|
115
|
+
exit EXIT_SUCCESS
|
116
|
+
end
|
117
|
+
# STDOUT.puts "#{ pid }"
|
118
|
+
exit!
|
119
|
+
end
|
120
|
+
exit!
|
121
|
+
else
|
122
|
+
@daemon = false
|
123
|
+
yield
|
124
|
+
exit EXIT_SUCCESS
|
125
|
+
end
|
126
|
+
#--}}}
|
127
|
+
end
|
128
|
+
def gen_pidfile name = nil
|
129
|
+
#--{{{
|
130
|
+
gen_pidfilepath
|
131
|
+
|
132
|
+
begin
|
133
|
+
FileUtils::mkdir_p(File::dirname(@pidfilepath))
|
134
|
+
rescue
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
|
138
|
+
locked = nil
|
139
|
+
no_other_feeder = nil
|
140
|
+
|
141
|
+
2.times do
|
142
|
+
locked = false
|
143
|
+
no_other_feeder = false
|
144
|
+
|
145
|
+
@pidfile =
|
146
|
+
begin
|
147
|
+
open @pidfilepath, File::CREAT | File::EXCL | File::RDWR
|
148
|
+
rescue
|
149
|
+
open @pidfilepath, File::RDWR
|
150
|
+
end
|
151
|
+
|
152
|
+
ret = @pidfile.posixlock(File::LOCK_EX | File::LOCK_NB)
|
153
|
+
locked = (ret == 0)
|
154
|
+
|
155
|
+
begin
|
156
|
+
pid = Integer(IO::read(@pidfilepath)) rescue nil
|
157
|
+
|
158
|
+
unless pid
|
159
|
+
no_other_feeder = true
|
160
|
+
break
|
161
|
+
end
|
162
|
+
|
163
|
+
if Util::alive?(pid)
|
164
|
+
no_other_feeder = Process::pid == pid ? true : false
|
165
|
+
#no_other_feeder = false
|
166
|
+
#else
|
167
|
+
#no_other_feeder = false
|
168
|
+
#end
|
169
|
+
break
|
170
|
+
else
|
171
|
+
no_other_feeder = true
|
172
|
+
STDERR.puts "WARNING : process <#{ pid }> died holding lock on <#{ @pidfilepath }>"
|
173
|
+
STDERR.puts "WARNING : attempting autorecovery!"
|
174
|
+
break if locked
|
175
|
+
STDERR.puts "WARNING : your NFS locking setup is FUBAR - iptables or firewall issues!"
|
176
|
+
STDERR.puts "WARNING : attempting autorecovery!"
|
177
|
+
FileUtils::rm_f @pidfilepath
|
178
|
+
4.times{ sleep rand }
|
179
|
+
end
|
180
|
+
|
181
|
+
rescue Exception => e
|
182
|
+
STDERR.puts "WARNING : #{ e.message } (#{ e.class })"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
unless(locked and no_other_feeder)
|
188
|
+
pid = Integer(IO::read(@pidfilepath)) rescue 'UNKNOWN'
|
189
|
+
if @options['quiet']
|
190
|
+
exit EXIT_FAILURE
|
191
|
+
else
|
192
|
+
abort "process <#{ pid }> is already feeding from this queue"
|
193
|
+
end
|
194
|
+
else
|
195
|
+
@pidfile.chmod 0600 rescue nil
|
196
|
+
@pidfile.rewind
|
197
|
+
@pidfile.sync = true
|
198
|
+
@pidfile.print Process::pid
|
199
|
+
@pidfile.truncate @pidfile.pos
|
200
|
+
@pidfile.flush
|
201
|
+
|
202
|
+
at_exit do
|
203
|
+
FileUtils::rm_f @pidfilepath rescue nil
|
204
|
+
@pidfile.posixlock File::LOCK_UN rescue nil
|
205
|
+
@pidfile.close rescue nil
|
206
|
+
end
|
207
|
+
end
|
208
|
+
#--}}}
|
209
|
+
end
|
210
|
+
def gen_pidfilepath
|
211
|
+
#--{{{
|
212
|
+
# @pidfilepath ||= gen_feeder_name
|
213
|
+
@pidfilepath ||= File::join(@dot_rq_dir, 'pid')
|
214
|
+
#--}}}
|
215
|
+
end
|
216
|
+
def gen_feeder_name path = nil
|
217
|
+
#--{{{
|
218
|
+
path ||= (@options['name'] || @qpath)
|
219
|
+
path = Util::realpath(path).gsub(%r|/|o, '_')
|
220
|
+
#File::join(Util::realpath('~'), ".#{ path }.feeder")
|
221
|
+
basename = ".#{ Util::host }_#{ path }.feeder".gsub(%r/_+/,'_')
|
222
|
+
dirname = Util::realpath '~'
|
223
|
+
File::join dirname, basename
|
224
|
+
#--}}}
|
225
|
+
end
|
226
|
+
def install_signal_handlers
|
227
|
+
#--{{{
|
228
|
+
if @daemon or ENV['RQ_SIGNALS']
|
229
|
+
$rq_signaled = false
|
230
|
+
$rq_sighup = false
|
231
|
+
$rq_sigterm = false
|
232
|
+
$rq_sigint = false
|
233
|
+
trap('SIGHUP') do
|
234
|
+
$rq_signaled = $rq_sighup = 'SIGHUP'
|
235
|
+
if nothing_running?
|
236
|
+
warn{ "signal <SIGHUP>" }
|
237
|
+
handle_signal
|
238
|
+
else
|
239
|
+
warn{ "finishing running jobs before handling signal" }
|
240
|
+
end
|
241
|
+
end
|
242
|
+
trap('SIGTERM') do
|
243
|
+
$rq_signaled = $rq_sigterm = 'SIGTERM'
|
244
|
+
if nothing_running?
|
245
|
+
warn{ "signal <SIGTERM>" }
|
246
|
+
handle_signal
|
247
|
+
else
|
248
|
+
warn{ "finishing running jobs before handling signal" }
|
249
|
+
end
|
250
|
+
end
|
251
|
+
trap('SIGINT') do
|
252
|
+
$rq_signaled = $rq_sigint = 'SIGINT'
|
253
|
+
if nothing_running?
|
254
|
+
warn{ "signal <SIGINT>" }
|
255
|
+
handle_signal
|
256
|
+
else
|
257
|
+
warn{ "finishing running jobs before handling signal" }
|
258
|
+
end
|
259
|
+
end
|
260
|
+
@jrd.install_signal_handlers
|
261
|
+
else
|
262
|
+
%w(SIGHUP SIGTERM SIGINT).each do |sig|
|
263
|
+
trap(sig) do
|
264
|
+
warn{ "signal <#{ sig }>" }
|
265
|
+
warn{ "not cleaning up - only daemon mode cleans up!" }
|
266
|
+
exit
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
#--}}}
|
271
|
+
end
|
272
|
+
def install_redirects
|
273
|
+
#--{{{
|
274
|
+
if @daemon
|
275
|
+
open('/dev/null','r+') do |f|
|
276
|
+
STDIN.reopen f
|
277
|
+
STDOUT.reopen f
|
278
|
+
STDERR.reopen f
|
279
|
+
end
|
280
|
+
end
|
281
|
+
#--}}}
|
282
|
+
end
|
283
|
+
def fill_morgue
|
284
|
+
#--{{{
|
285
|
+
debug{ "filling morgue..." }
|
286
|
+
transaction do
|
287
|
+
deadjobs = @q.getdeadjobs @started
|
288
|
+
deadjobs.each do |job|
|
289
|
+
@q.jobisdead job
|
290
|
+
unless job['restartable']
|
291
|
+
info{ "burried job <#{ job['jid'] }>" }
|
292
|
+
else
|
293
|
+
warn{ "dead job <#{ job['jid'] }> will be restarted" }
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
debug{ "filled morgue" }
|
298
|
+
#--}}}
|
299
|
+
end
|
300
|
+
def reap_zombie_ios
|
301
|
+
#--{{{
|
302
|
+
debug{ "reaping zombie ios" }
|
303
|
+
begin
|
304
|
+
transaction do
|
305
|
+
stdin, stdout, stderr, data = @q.stdin, @q.stdout, @q.stderr, @q.data
|
306
|
+
jids = @q.execute("select jid from jobs").map{|tuple| Integer tuple.first}
|
307
|
+
jids = jids.inject({}){|h,jid| h.update jid => true}
|
308
|
+
%w[ stdin stdout stderr data ].each do |d|
|
309
|
+
Dir::glob(File::join(@q.send(d), "*")).each do |iof|
|
310
|
+
begin
|
311
|
+
jid = Integer iof[%r/\d+\s*$/]
|
312
|
+
unless jids[jid]
|
313
|
+
debug{ "removing zombie io <#{ iof }>" }
|
314
|
+
FileUtils::rm_rf iof
|
315
|
+
end
|
316
|
+
rescue
|
317
|
+
next
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
rescue Exception => e # because this is a non-essential function
|
323
|
+
warn{ e }
|
324
|
+
end
|
325
|
+
debug{ "reaped" }
|
326
|
+
#--}}}
|
327
|
+
end
|
328
|
+
def handle_signal
|
329
|
+
#--{{{
|
330
|
+
if $rq_sigterm or $rq_sigint
|
331
|
+
reap_jobs(reap_only = true) until nothing_running?
|
332
|
+
info{ "** STOPPING **" }
|
333
|
+
@jrd.shutdown rescue nil
|
334
|
+
@pidfile.posixlock File::LOCK_UN
|
335
|
+
exit EXIT_SUCCESS
|
336
|
+
end
|
337
|
+
|
338
|
+
if $rq_sighup
|
339
|
+
reap_jobs(reap_only = true) until nothing_running?
|
340
|
+
info{ "** RESTARTING **" }
|
341
|
+
info{ "** ARGV <#{ @cmd }> **" }
|
342
|
+
begin
|
343
|
+
@jrd.shutdown rescue nil
|
344
|
+
Util::uncache __FILE__
|
345
|
+
@pidfile.posixlock File::LOCK_UN
|
346
|
+
Util::exec @cmd
|
347
|
+
rescue Exception => e
|
348
|
+
fatal{"** FAILED TO RESTART! **"}
|
349
|
+
fatal{ e }
|
350
|
+
exit EXIT_FAILURE
|
351
|
+
end
|
352
|
+
end
|
353
|
+
#--}}}
|
354
|
+
end
|
355
|
+
def throttle rate = @min_sleep
|
356
|
+
#--{{{
|
357
|
+
if Numeric === rate and rate > 0
|
358
|
+
if defined? @last_throttle_time and @last_throttle_time
|
359
|
+
elapsed = Time.now - @last_throttle_time
|
360
|
+
timeout = rate - elapsed
|
361
|
+
if timeout > 0
|
362
|
+
timeout = timeout + rand(rate * 0.10)
|
363
|
+
debug{ "throttle rate of <#{ rate }> exceeded - sleeping <#{ timeout }>" }
|
364
|
+
sleep timeout
|
365
|
+
end
|
366
|
+
end
|
367
|
+
@last_throttle_time = Time.now
|
368
|
+
end
|
369
|
+
yield
|
370
|
+
#--}}}
|
371
|
+
end
|
372
|
+
def start_jobs
|
373
|
+
#--{{{
|
374
|
+
debug{ "starting jobs..." }
|
375
|
+
n_started = 0
|
376
|
+
transaction do
|
377
|
+
until busy?
|
378
|
+
break unless((job = @q.getjob))
|
379
|
+
start_job job
|
380
|
+
n_started += 1
|
381
|
+
end
|
382
|
+
end
|
383
|
+
debug{ "<#{ n_started }> jobs started" }
|
384
|
+
n_started
|
385
|
+
#--}}}
|
386
|
+
end
|
387
|
+
def start_job job
|
388
|
+
#--{{{
|
389
|
+
jid, command = job['jid'], job['command']
|
390
|
+
|
391
|
+
#
|
392
|
+
# we setup state slightly prematurely so jobrunner will have it availible
|
393
|
+
#
|
394
|
+
job['state'] = 'running'
|
395
|
+
job['started'] = Util::timestamp Time::now
|
396
|
+
job['runner'] = Util::hostname
|
397
|
+
|
398
|
+
job['stdout'] = @q.stdout4 jid
|
399
|
+
job['stderr'] = @q.stderr4 jid
|
400
|
+
|
401
|
+
jr = @jrd.runner job
|
402
|
+
cid = jr.cid
|
403
|
+
|
404
|
+
if jr and cid
|
405
|
+
jr.run
|
406
|
+
job['pid'] = cid
|
407
|
+
@children[cid] = job
|
408
|
+
@q.jobisrunning job
|
409
|
+
info{ "started - jid <#{ job['jid'] }> pid <#{ job['pid'] }> command <#{ job['command'] }>" }
|
410
|
+
else
|
411
|
+
error{ "not started - jid <#{ job['jid'] }> command <#{ job['command'] }>" }
|
412
|
+
end
|
413
|
+
|
414
|
+
cid
|
415
|
+
#--}}}
|
416
|
+
end
|
417
|
+
def nothing_running?
|
418
|
+
#--{{{
|
419
|
+
@children.size == 0
|
420
|
+
#--}}}
|
421
|
+
end
|
422
|
+
def reap_jobs reap_only = false, blocking = true
|
423
|
+
#--{{{
|
424
|
+
debug{ "reaping jobs..." }
|
425
|
+
reaped = []
|
426
|
+
|
427
|
+
cid = status = nil
|
428
|
+
|
429
|
+
if blocking
|
430
|
+
if busy? or reap_only
|
431
|
+
cid, status = @jrd.waitpid2 -1, Process::WUNTRACED
|
432
|
+
else
|
433
|
+
loop do
|
434
|
+
debug{ "not busy - busywait loop" }
|
435
|
+
cid, status = @jrd.waitpid2 -1, Process::WNOHANG | Process::WUNTRACED
|
436
|
+
break if cid
|
437
|
+
start_jobs unless $rq_signaled
|
438
|
+
break if busy?
|
439
|
+
cid, status = @jrd.waitpid2 -1, Process::WNOHANG | Process::WUNTRACED
|
440
|
+
break if cid
|
441
|
+
sleep 4.2
|
442
|
+
end
|
443
|
+
cid, status = @jrd.waitpid2 -1, Process::WUNTRACED unless cid
|
444
|
+
end
|
445
|
+
else
|
446
|
+
cid, status = @jrd.waitpid2 -1, Process::WNOHANG | Process::WUNTRACED
|
447
|
+
end
|
448
|
+
|
449
|
+
if cid and status
|
450
|
+
job = @children[cid]
|
451
|
+
finish_job job, status
|
452
|
+
|
453
|
+
transaction do
|
454
|
+
loopno = 0
|
455
|
+
loop do
|
456
|
+
@q.jobisdone job
|
457
|
+
@children.delete cid
|
458
|
+
reaped << cid
|
459
|
+
|
460
|
+
start_jobs unless reap_only or $rq_signaled
|
461
|
+
|
462
|
+
if @children.size == 0 or loopno > 42
|
463
|
+
sleep 8 if loopno > 42 # wow - we are CRANKING through jobs so BACK OFF!!
|
464
|
+
break
|
465
|
+
else
|
466
|
+
sleep 0.1
|
467
|
+
cid, status = @jrd.waitpid2 -1, Process::WNOHANG | Process::WUNTRACED
|
468
|
+
break unless cid and status
|
469
|
+
job = @children[cid]
|
470
|
+
finish_job job, status
|
471
|
+
end
|
472
|
+
loopno += 1
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|
476
|
+
debug{ "<#{ reaped.size }> jobs reaped" }
|
477
|
+
reaped
|
478
|
+
#--}}}
|
479
|
+
end
|
480
|
+
def finish_job job, status
|
481
|
+
#--{{{
|
482
|
+
job['finished'] = Util::timestamp(Time::now)
|
483
|
+
job['elapsed'] = Util::stamptime(job['finished']) - Util::stamptime(job['started'])
|
484
|
+
t = status.exitstatus rescue nil
|
485
|
+
job['exit_status'] = t
|
486
|
+
job['state'] = 'finished'
|
487
|
+
if t and t == 0
|
488
|
+
info{ "finished - jid <#{ job['jid'] }> pid <#{ job['pid'] }> exit_status <#{ job['exit_status'] }>" }
|
489
|
+
else
|
490
|
+
warn{ "finished - jid <#{ job['jid'] }> pid <#{ job['pid'] }> exit_status <#{ job['exit_status'] }>" }
|
491
|
+
end
|
492
|
+
#--}}}
|
493
|
+
end
|
494
|
+
def transaction
|
495
|
+
#--{{{
|
496
|
+
ret = nil
|
497
|
+
if @in_transaction
|
498
|
+
ret = yield
|
499
|
+
else
|
500
|
+
begin
|
501
|
+
@in_transaction = true
|
502
|
+
@q.transaction{ ret = yield }
|
503
|
+
ensure
|
504
|
+
@in_transaction = false
|
505
|
+
end
|
506
|
+
end
|
507
|
+
ret
|
508
|
+
#--}}}
|
509
|
+
end
|
510
|
+
def busy?
|
511
|
+
#--{{{
|
512
|
+
@children.size >= @max_feed
|
513
|
+
#--}}}
|
514
|
+
end
|
515
|
+
def relax
|
516
|
+
#--{{{
|
517
|
+
seconds = rand(@max_sleep - @min_sleep + 1) + @min_sleep
|
518
|
+
debug{ "relaxing <#{ seconds }>" }
|
519
|
+
sleep seconds
|
520
|
+
#--}}}
|
521
|
+
end
|
522
|
+
#--}}}
|
523
|
+
end # class Feeder
|
524
|
+
#--}}}
|
525
|
+
end # module RQ
|
526
|
+
$__rq_feeder__ = __FILE__
|
527
|
+
end
|