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/querier.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
unless defined? $__rq_queryier__
|
2
|
+
module RQ
|
3
|
+
#--{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require LIBDIR + 'mainhelper'
|
8
|
+
|
9
|
+
#
|
10
|
+
# a Querier simply takes an sql where clause (such as 'jid = 42') from the
|
11
|
+
# command line, queries the queue, and dumps a valid yaml representation of
|
12
|
+
# the tuples returned. the output of a Querier can be used as the input to
|
13
|
+
# a Deleter or Submitter, etc.
|
14
|
+
#
|
15
|
+
#
|
16
|
+
class Querier < MainHelper
|
17
|
+
#--{{{
|
18
|
+
def query
|
19
|
+
#--{{{
|
20
|
+
set_q
|
21
|
+
|
22
|
+
@q.qdb.transaction_retries = 1
|
23
|
+
|
24
|
+
where_clause = @argv.join ' '
|
25
|
+
|
26
|
+
if where_clause.empty? and stdin?
|
27
|
+
debug{ "reading where_clause from stdin" }
|
28
|
+
while((buf = stdin.gets))
|
29
|
+
buf.strip!
|
30
|
+
buf.gsub! %r/#.*$/o, ''
|
31
|
+
next if buf.empty?
|
32
|
+
where_clause << "#{ buf } "
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
@q.query(where_clause, &dumping_yaml_tuples)
|
37
|
+
#--}}}
|
38
|
+
end
|
39
|
+
def query
|
40
|
+
#--{{{
|
41
|
+
set_q
|
42
|
+
|
43
|
+
@q.qdb.transaction_retries = 1
|
44
|
+
|
45
|
+
simple_pat = %r/^\s*([^=\s!~]+)(=~|!~|!=|==|=)([^=\s]+)\s*$/ox
|
46
|
+
simple_query = @argv.select{|arg| arg !~ simple_pat }.empty?
|
47
|
+
|
48
|
+
where_clause =
|
49
|
+
if simple_query
|
50
|
+
wc = []
|
51
|
+
|
52
|
+
@argv.each do |arg|
|
53
|
+
m = simple_pat.match(arg).to_a[1..-1]
|
54
|
+
field, op, value = m[0], m[1], m[2..-1].join
|
55
|
+
op =
|
56
|
+
case op
|
57
|
+
when '=', '=='
|
58
|
+
'='
|
59
|
+
when '!='
|
60
|
+
'!='
|
61
|
+
when '=~'
|
62
|
+
'like'
|
63
|
+
when '!~'
|
64
|
+
'not like'
|
65
|
+
end
|
66
|
+
|
67
|
+
quoted = (value =~ %r/^\s*'.*'\s*$/o)
|
68
|
+
numeric = begin; Float(value); true; rescue; false; end
|
69
|
+
|
70
|
+
value = "'#{ value }'" unless quoted or numeric
|
71
|
+
|
72
|
+
wc << "(#{ field } #{ op } #{ value })"
|
73
|
+
end
|
74
|
+
|
75
|
+
wc.join ' and '
|
76
|
+
else
|
77
|
+
@argv.join ' '
|
78
|
+
end
|
79
|
+
|
80
|
+
if where_clause.strip.empty? and stdin?
|
81
|
+
debug{ "reading where_clause from stdin" }
|
82
|
+
while((buf = stdin.gets))
|
83
|
+
buf.strip!
|
84
|
+
buf.gsub! %r/#.*$/o, ''
|
85
|
+
next if buf.empty?
|
86
|
+
where_clause << "#{ buf } "
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
@q.query(where_clause, &dumping_yaml_tuples)
|
91
|
+
#--}}}
|
92
|
+
end
|
93
|
+
#--}}}
|
94
|
+
end # class Queryier
|
95
|
+
#--}}}
|
96
|
+
end # module RQ
|
97
|
+
$__rq_queryier__ = __FILE__
|
98
|
+
end
|
data/lib/rq/rails.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
if defined?(Rails)
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
class << self
|
6
|
+
def qpath *arg
|
7
|
+
@qpath = arg.shift unless arg.empty?
|
8
|
+
@qpath ||= File.join(RAILS_ROOT, 'q')
|
9
|
+
@qpath
|
10
|
+
end
|
11
|
+
|
12
|
+
def q
|
13
|
+
defined?(@q) ? @q : qinit
|
14
|
+
end
|
15
|
+
|
16
|
+
def qinit
|
17
|
+
unless test ?e, qpath
|
18
|
+
cmd = "rq #{ qpath } create"
|
19
|
+
system cmd or abort "cmd <#{ cmd }> failed with <#{ $?.inspect }>"
|
20
|
+
cmd = "cp `which rqmailer` #{ qpath }/bin"
|
21
|
+
system cmd or abort "cmd <#{ cmd }> failed with <#{ $?.inspect }>"
|
22
|
+
end
|
23
|
+
(( logger = Logger.new STDERR )).level = Logger::FATAL
|
24
|
+
@q = RQ::JobQueue.new qpath, 'logger' => logger
|
25
|
+
@q.extend qextension
|
26
|
+
@q
|
27
|
+
end
|
28
|
+
|
29
|
+
def qextension
|
30
|
+
Module.new do
|
31
|
+
def rqmailer config, template = nil, submission = {}
|
32
|
+
config = YAML.load config if String === config
|
33
|
+
|
34
|
+
### clean up keys
|
35
|
+
config = config.inject({}){|h,kv| k, v = kv; h.update k.to_s => v}
|
36
|
+
submission = submission.inject({}){|h,kv| k, v = kv; h.update k.to_s => v}
|
37
|
+
|
38
|
+
command = (config["command"] || config["cmd"]) or raise "no command in <#{ config.inspect }>!"
|
39
|
+
|
40
|
+
mconfig = config["mail"] || config
|
41
|
+
attachements = [ mconfig["attach"] ].flatten.compact
|
42
|
+
|
43
|
+
tag = "rqmailer"
|
44
|
+
command = "rqmailer ### #{ command }"
|
45
|
+
|
46
|
+
submission["tag"] ||= tag
|
47
|
+
submission["command"] = command
|
48
|
+
|
49
|
+
tmpdir = File.join RAILS_ROOT, 'tmp', Process.pid.to_s, '.rqmailer.d'
|
50
|
+
FileUtils.mkdir_p tmpdir
|
51
|
+
begin
|
52
|
+
open(File.join(tmpdir, 'config'), 'w') do |fd|
|
53
|
+
fd.write config.to_yaml
|
54
|
+
end
|
55
|
+
if template
|
56
|
+
open(File.join(tmpdir, 'template'), 'w') do |fd|
|
57
|
+
fd.write template
|
58
|
+
end
|
59
|
+
end
|
60
|
+
d = File.join(tmpdir, "attachements")
|
61
|
+
FileUtils.mkdir_p d
|
62
|
+
attachements.each do |attachment|
|
63
|
+
FileUtils.cp attachment, d
|
64
|
+
end
|
65
|
+
|
66
|
+
submission["data"] = tmpdir
|
67
|
+
job = nil
|
68
|
+
submit(submission){|job|}
|
69
|
+
job
|
70
|
+
ensure
|
71
|
+
FileUtils.rm_rf tmpdir
|
72
|
+
end
|
73
|
+
end
|
74
|
+
alias_method "mailrun", "rqmailer"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
data/lib/rq/recoverer.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
unless defined? $__rq_recoverer__
|
2
|
+
module RQ
|
3
|
+
#--{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require LIBDIR + 'mainhelper'
|
8
|
+
|
9
|
+
class Recoverer < MainHelper
|
10
|
+
#--{{{
|
11
|
+
def recover
|
12
|
+
#--{{{
|
13
|
+
set_q
|
14
|
+
|
15
|
+
bool = @q.recover! ? true : false
|
16
|
+
puts "---"
|
17
|
+
puts "recovered : #{ bool }"
|
18
|
+
|
19
|
+
EXIT_SUCCESS
|
20
|
+
#--}}}
|
21
|
+
end
|
22
|
+
alias recover! recover
|
23
|
+
#--}}}
|
24
|
+
end # class Recoverer
|
25
|
+
#--}}}
|
26
|
+
end # module RQ
|
27
|
+
$__rq_recoverer__ = __FILE__
|
28
|
+
end
|
data/lib/rq/refresher.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
unless defined? $__rq_refresher__
|
2
|
+
module RQ
|
3
|
+
#--{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
#
|
8
|
+
# the job of the Refresher is to maintain a _lease_ on a file that has been
|
9
|
+
# locked. the method is simply to touch the file at a certain interval
|
10
|
+
# thereby keeping it 'fresh'. a separate process, vs. a thread, is used for
|
11
|
+
# this task to eliminate any chance that the ruby interpreter might put all
|
12
|
+
# threads to sleep for some blocking tasks, like fcntl based locks which are
|
13
|
+
# used heavily in RQ, resulting in a a prematurely stale lockfile
|
14
|
+
#
|
15
|
+
class Refresher
|
16
|
+
#--{{{
|
17
|
+
SIGNALS = %w(SIGTERM SIGINT SIGKILL)
|
18
|
+
attr :path
|
19
|
+
attr :pid
|
20
|
+
attr :refresh_rate
|
21
|
+
def initialize path, refresh_rate = 8
|
22
|
+
#--{{{
|
23
|
+
@path = path
|
24
|
+
File::stat path
|
25
|
+
@refresh_rate = Float refresh_rate
|
26
|
+
@pipe = IO::pipe
|
27
|
+
if((@pid = Util::fork))
|
28
|
+
@pipe.last.close
|
29
|
+
@pipe = @pipe.first
|
30
|
+
@thread = Thread::new{loop{@pipe.gets}}
|
31
|
+
Process::detach @pid
|
32
|
+
else
|
33
|
+
begin
|
34
|
+
pid = Process::pid
|
35
|
+
ppid = Process::ppid
|
36
|
+
$0 = "#{ path }.refresher.#{ pid }"
|
37
|
+
SIGNALS.each{|sig| trap(sig){ raise }}
|
38
|
+
@pipe.first.close
|
39
|
+
@pipe = @pipe.last
|
40
|
+
loop do
|
41
|
+
FileUtils::touch @path
|
42
|
+
sleep @refresh_rate
|
43
|
+
Process::kill 0, ppid
|
44
|
+
@pipe.puts pid
|
45
|
+
end
|
46
|
+
rescue Exception => e
|
47
|
+
exit!
|
48
|
+
end
|
49
|
+
end
|
50
|
+
#--}}}
|
51
|
+
end
|
52
|
+
def kill
|
53
|
+
#--{{{
|
54
|
+
begin
|
55
|
+
@thread.kill rescue nil
|
56
|
+
@pipe.close rescue nil
|
57
|
+
SIGNALS.each{|sig| Process::kill sig, @pid rescue nil}
|
58
|
+
ensure
|
59
|
+
=begin
|
60
|
+
n = 42
|
61
|
+
dead = false
|
62
|
+
begin
|
63
|
+
n.times do |i|
|
64
|
+
Process::kill 0, @pid
|
65
|
+
sleep 1
|
66
|
+
end
|
67
|
+
rescue Errno::ESRCH
|
68
|
+
dead = true
|
69
|
+
end
|
70
|
+
raise "runaway refresher <#{ @pid }> must be killed!" unless dead
|
71
|
+
=end
|
72
|
+
end
|
73
|
+
#--}}}
|
74
|
+
end
|
75
|
+
#--}}}
|
76
|
+
end # class Refresher
|
77
|
+
#--}}}
|
78
|
+
end # module RQ
|
79
|
+
$__rq_refresher__ = __FILE__
|
80
|
+
end
|
data/lib/rq/relayer.rb
ADDED
@@ -0,0 +1,283 @@
|
|
1
|
+
unless defined? $__rq_relayer__
|
2
|
+
module RQ
|
3
|
+
#--{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require LIBDIR + 'mainhelper'
|
8
|
+
require LIBDIR + 'job'
|
9
|
+
require LIBDIR + 'jobrunner'
|
10
|
+
require LIBDIR + 'jobrunnerdaemon'
|
11
|
+
require LIBDIR + 'jobqueue'
|
12
|
+
|
13
|
+
class Relayer < MainHelper
|
14
|
+
#--{{{
|
15
|
+
DEFAULT_MIN_SLEEP = 42
|
16
|
+
DEFAULT_MAX_SLEEP = 240
|
17
|
+
DEFAULT_RELAY = 16
|
18
|
+
|
19
|
+
class << self
|
20
|
+
#--{{{
|
21
|
+
attr :min_sleep, true
|
22
|
+
attr :max_sleep, true
|
23
|
+
attr :relay, true
|
24
|
+
#--}}}
|
25
|
+
end
|
26
|
+
|
27
|
+
def relay
|
28
|
+
#--{{{
|
29
|
+
daemon do
|
30
|
+
gen_pidfile
|
31
|
+
@main.init_logging
|
32
|
+
@logger = @main.logger
|
33
|
+
|
34
|
+
set_q
|
35
|
+
|
36
|
+
#
|
37
|
+
# munge @q/@qpath to set there
|
38
|
+
#
|
39
|
+
@here = @q
|
40
|
+
@qpath = realpath @main.argv.shift
|
41
|
+
set_q
|
42
|
+
@there = @q
|
43
|
+
@q = @here
|
44
|
+
@hdb = @here.qdb
|
45
|
+
@tdb = @there.qdb
|
46
|
+
|
47
|
+
@pid = Process::pid
|
48
|
+
@cmd = @main.cmd
|
49
|
+
@started = Util::timestamp
|
50
|
+
@min_sleep = Integer(@options['min_sleep'] || defval('min_sleep'))
|
51
|
+
@max_sleep = Integer(@options['max_sleep'] || defval('max_sleep'))
|
52
|
+
@relay = Integer(@options['number'] || defval('relay'))
|
53
|
+
|
54
|
+
@transactions = {}
|
55
|
+
|
56
|
+
|
57
|
+
install_signal_handlers
|
58
|
+
|
59
|
+
info{ "** STARTED **" }
|
60
|
+
info{ "version <#{ RQ::VERSION }>" }
|
61
|
+
info{ "cmd <#{ @cmd }>" }
|
62
|
+
info{ "pid <#{ @pid }>" }
|
63
|
+
info{ "pidfile <#{ @pidfile.path }>" }
|
64
|
+
info{ "here <#{ @here.path }>" }
|
65
|
+
info{ "there <#{ @there.path }>" }
|
66
|
+
|
67
|
+
debug{ "mode <#{ @mode }>" }
|
68
|
+
debug{ "min_sleep <#{ @min_sleep }>" }
|
69
|
+
debug{ "max_sleep <#{ @max_sleep }>" }
|
70
|
+
debug{ "relay <#{ @relay }>" }
|
71
|
+
|
72
|
+
exit
|
73
|
+
|
74
|
+
loop do
|
75
|
+
handle_signal if $rq_signaled
|
76
|
+
throttle(@min_sleep) do
|
77
|
+
reap_and_sow
|
78
|
+
relax
|
79
|
+
end
|
80
|
+
end
|
81
|
+
=begin
|
82
|
+
loop do
|
83
|
+
handle_signal if $rq_signaled
|
84
|
+
throttle(@min_sleep) do
|
85
|
+
start_jobs unless busy?
|
86
|
+
if nothing_running?
|
87
|
+
relax
|
88
|
+
else
|
89
|
+
reap_jobs
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
=end
|
94
|
+
end
|
95
|
+
#--}}}
|
96
|
+
end
|
97
|
+
|
98
|
+
def daemon
|
99
|
+
#--{{{
|
100
|
+
if @options['daemon']
|
101
|
+
fork do
|
102
|
+
Process::setsid
|
103
|
+
fork do
|
104
|
+
Dir::chdir(Util.realpath('~'))
|
105
|
+
File::umask 0
|
106
|
+
open('/dev/null','r+') do |f|
|
107
|
+
STDIN.reopen f
|
108
|
+
STDOUT.reopen f
|
109
|
+
STDERR.reopen f
|
110
|
+
end
|
111
|
+
@daemon = true
|
112
|
+
yield
|
113
|
+
exit EXIT_SUCCESS
|
114
|
+
end
|
115
|
+
exit!
|
116
|
+
end
|
117
|
+
exit!
|
118
|
+
else
|
119
|
+
@daemon = false
|
120
|
+
yield
|
121
|
+
exit EXIT_SUCCESS
|
122
|
+
end
|
123
|
+
#--}}}
|
124
|
+
end
|
125
|
+
def gen_pidfile name = nil
|
126
|
+
#--{{{
|
127
|
+
name ||= gen_relayer_name(@options['name'] || @qpath)
|
128
|
+
@pidfile =
|
129
|
+
begin
|
130
|
+
open name, File::CREAT | File::EXCL | File::RDWR
|
131
|
+
rescue
|
132
|
+
open name, File::RDWR
|
133
|
+
end
|
134
|
+
unless @pidfile and @pidfile.posixlock(File::LOCK_EX | File::LOCK_NB)
|
135
|
+
pid = IO::read(name) rescue nil
|
136
|
+
pid ||= 'unknown'
|
137
|
+
if @options['quiet']
|
138
|
+
exit EXIT_FAILURE
|
139
|
+
else
|
140
|
+
raise "process <#{ pid }> is already relaying from this queue"
|
141
|
+
end
|
142
|
+
else
|
143
|
+
@pidfile.rewind
|
144
|
+
@pidfile.sync = true
|
145
|
+
@pidfile.print Process::pid
|
146
|
+
@pidfile.truncate @pidfile.pos
|
147
|
+
at_exit{ FileUtils::rm_f name rescue nil }
|
148
|
+
end
|
149
|
+
#--}}}
|
150
|
+
end
|
151
|
+
def gen_relayer_name path
|
152
|
+
#--{{{
|
153
|
+
path = Util::realpath(path).gsub(%r|/|o, '_')
|
154
|
+
File::join(Util::realpath('~'), ".#{ path }.relayer")
|
155
|
+
#--}}}
|
156
|
+
end
|
157
|
+
def install_signal_handlers
|
158
|
+
#--{{{
|
159
|
+
if @daemon
|
160
|
+
$rq_signaled = false
|
161
|
+
$rq_sighup = false
|
162
|
+
$rq_sigterm = false
|
163
|
+
$rq_sigint = false
|
164
|
+
trap('SIGHUP') do
|
165
|
+
$rq_signaled = $rq_sighup = 'SIGHUP'
|
166
|
+
warn{ "signal <SIGHUP>" }
|
167
|
+
warn{ "finishing running jobs before handling signal" }
|
168
|
+
end
|
169
|
+
trap('SIGTERM') do
|
170
|
+
$rq_signaled = $rq_sigterm = 'SIGTERM'
|
171
|
+
warn{ "signal <SIGTERM>" }
|
172
|
+
warn{ "finishing running jobs before handling signal" }
|
173
|
+
end
|
174
|
+
trap('SIGINT') do
|
175
|
+
$rq_signaled = $rq_sigint = 'SIGINT'
|
176
|
+
warn{ "signal <SIGINT>" }
|
177
|
+
warn{ "finishing running jobs before handling signal" }
|
178
|
+
end
|
179
|
+
@jrd.install_signal_handlers
|
180
|
+
end
|
181
|
+
#--}}}
|
182
|
+
end
|
183
|
+
def handle_signal
|
184
|
+
#--{{{
|
185
|
+
if $rq_sigterm or $rq_sigint
|
186
|
+
reap_jobs(reap_only = true) until nothing_running?
|
187
|
+
info{ "** STOPPING **" }
|
188
|
+
@jrd.shutdown rescue nil
|
189
|
+
@pidfile.posixlock File::LOCK_UN
|
190
|
+
exit EXIT_SUCCESS
|
191
|
+
end
|
192
|
+
|
193
|
+
if $rq_sighup
|
194
|
+
reap_jobs(reap_only = true) until nothing_running?
|
195
|
+
info{ "** RESTARTING **" }
|
196
|
+
@jrd.shutdown rescue nil
|
197
|
+
Util::uncache __FILE__
|
198
|
+
@pidfile.posixlock File::LOCK_UN
|
199
|
+
Util::exec @cmd
|
200
|
+
end
|
201
|
+
#--}}}
|
202
|
+
end
|
203
|
+
def throttle rate = @min_sleep
|
204
|
+
#--{{{
|
205
|
+
if Numeric === rate and rate > 0
|
206
|
+
if defined? @last_throttle_time and @last_throttle_time
|
207
|
+
elapsed = Time.now - @last_throttle_time
|
208
|
+
timeout = rate - elapsed
|
209
|
+
if timeout > 0
|
210
|
+
timeout = timeout + rand(rate * 0.10)
|
211
|
+
debug{ "throttle rate of <#{ rate }> exceeded - sleeping <#{ timeout }>" }
|
212
|
+
sleep timeout
|
213
|
+
end
|
214
|
+
end
|
215
|
+
@last_throttle_time = Time.now
|
216
|
+
end
|
217
|
+
yield
|
218
|
+
#--}}}
|
219
|
+
end
|
220
|
+
def transaction
|
221
|
+
#--{{{
|
222
|
+
ret = nil
|
223
|
+
if @in_transaction
|
224
|
+
ret = yield
|
225
|
+
else
|
226
|
+
begin
|
227
|
+
@in_transaction = true
|
228
|
+
@here.transaction do
|
229
|
+
@there.transaction do
|
230
|
+
ret = yield
|
231
|
+
end
|
232
|
+
end
|
233
|
+
ensure
|
234
|
+
@in_transaction = false
|
235
|
+
end
|
236
|
+
end
|
237
|
+
ret
|
238
|
+
#--}}}
|
239
|
+
end
|
240
|
+
def relax
|
241
|
+
#--{{{
|
242
|
+
seconds = rand(@max_sleep - @min_sleep + 1) + @min_sleep
|
243
|
+
debug{ "relaxing <#{ seconds }>" }
|
244
|
+
sleep seconds
|
245
|
+
#--}}}
|
246
|
+
end
|
247
|
+
|
248
|
+
#
|
249
|
+
# TODO - this will need to map jids here to jids there
|
250
|
+
#
|
251
|
+
def reap_and_sow
|
252
|
+
#--{{{
|
253
|
+
transaction{ reap and sow }
|
254
|
+
#--}}}
|
255
|
+
end
|
256
|
+
def reap
|
257
|
+
#--{{{
|
258
|
+
debug{ "reaping finished/dead jobs" }
|
259
|
+
|
260
|
+
sql = <<-sql
|
261
|
+
select jid from jobs where or state='running'
|
262
|
+
sql
|
263
|
+
tuples = hdb.execute sql
|
264
|
+
hjids = tuples.map{|t| t['jid']}
|
265
|
+
|
266
|
+
unless jids.empty
|
267
|
+
where_clauses = hjids.map{|hjid| "jid=#{ hjid }" }
|
268
|
+
where_clause = where_clauses.join ' or '
|
269
|
+
sql = <<-sql
|
270
|
+
select jid from jobs where state='finished' or state='dead' and (#{ where_clause })
|
271
|
+
sql
|
272
|
+
end
|
273
|
+
|
274
|
+
debug{ "reaped finished/dead jobs" }
|
275
|
+
self
|
276
|
+
#--}}}
|
277
|
+
end
|
278
|
+
#--}}}
|
279
|
+
end # class Relayer
|
280
|
+
#--}}}
|
281
|
+
end # module RQ
|
282
|
+
$__rq_relayer__ = __FILE__
|
283
|
+
end
|