rq 0.1.7
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/DEPENDS +5 -0
- data/HISTORY +26 -0
- data/README +552 -0
- data/TODO +13 -0
- data/VERSION +1 -0
- data/bin/rq +391 -0
- data/bin/rq-0.1.7 +410 -0
- data/install.rb +143 -0
- data/lib/rq-0.1.7.rb +82 -0
- data/lib/rq-0.1.7/backer.rb +27 -0
- data/lib/rq-0.1.7/configfile.rb +78 -0
- data/lib/rq-0.1.7/configurator.rb +36 -0
- data/lib/rq-0.1.7/creator.rb +23 -0
- data/lib/rq-0.1.7/defaultconfig.txt +5 -0
- data/lib/rq-0.1.7/deleter.rb +39 -0
- data/lib/rq-0.1.7/executor.rb +41 -0
- data/lib/rq-0.1.7/feeder.rb +367 -0
- data/lib/rq-0.1.7/job.rb +51 -0
- data/lib/rq-0.1.7/jobqueue.rb +432 -0
- data/lib/rq-0.1.7/jobrunner.rb +63 -0
- data/lib/rq-0.1.7/jobrunnerdaemon.rb +179 -0
- data/lib/rq-0.1.7/lister.rb +22 -0
- data/lib/rq-0.1.7/locker.rb +37 -0
- data/lib/rq-0.1.7/logging.rb +117 -0
- data/lib/rq-0.1.7/mainhelper.rb +53 -0
- data/lib/rq-0.1.7/qdb.rb +634 -0
- data/lib/rq-0.1.7/querier.rb +33 -0
- data/lib/rq-0.1.7/refresher.rb +72 -0
- data/lib/rq-0.1.7/sleepcycle.rb +46 -0
- data/lib/rq-0.1.7/snapshotter.rb +25 -0
- data/lib/rq-0.1.7/statuslister.rb +22 -0
- data/lib/rq-0.1.7/submitter.rb +90 -0
- data/lib/rq-0.1.7/updater.rb +95 -0
- data/lib/rq-0.1.7/usage.rb +609 -0
- data/lib/rq-0.1.7/util.rb +286 -0
- data/lib/rq.rb +84 -0
- data/rdoc.cmd +2 -0
- data/rq +2 -0
- data/rq.gemspec +36 -0
- data/rq.help +552 -0
- data/white_box/crontab +2 -0
- data/white_box/killrq +18 -0
- data/white_box/rq_killer +27 -0
- metadata +126 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
unless defined? $__rq_jobrunner__
|
2
|
+
module RQ
|
3
|
+
#{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require 'drb/drb'
|
8
|
+
|
9
|
+
require LIBDIR + 'util'
|
10
|
+
|
11
|
+
class JobRunner
|
12
|
+
#{{{
|
13
|
+
include DRbUndumped
|
14
|
+
attr :job
|
15
|
+
attr :jid
|
16
|
+
attr :cid
|
17
|
+
attr :shell
|
18
|
+
attr :command
|
19
|
+
alias pid cid
|
20
|
+
def initialize job
|
21
|
+
#{{{
|
22
|
+
@job = job
|
23
|
+
@jid = job['jid']
|
24
|
+
@command = job['command']
|
25
|
+
@shell = job['shell'] || 'bash'
|
26
|
+
@r,@w = IO::pipe
|
27
|
+
@env = {}
|
28
|
+
@job.fields.each do |field|
|
29
|
+
key = "RQ_#{ field }".upcase.gsub(%r/\s+/,'_')
|
30
|
+
val = @job[field]
|
31
|
+
@env[key] = "#{ val }"
|
32
|
+
end
|
33
|
+
@cid =
|
34
|
+
Util::fork do
|
35
|
+
begin
|
36
|
+
@env.each{|k,v| ENV[k] = v}
|
37
|
+
ENV['RQ_PID'] = "#{ $$ }"
|
38
|
+
@w.close
|
39
|
+
STDIN.reopen @r
|
40
|
+
if File::basename(@shell) == 'bash' || File::basename(@shell) == 'sh'
|
41
|
+
exec [@shell, "__rq_job__#{ @jid }__#{ File::basename(@shell) }__"], '--login'
|
42
|
+
else
|
43
|
+
exec [@shell, "__rq_job__#{ @jid }__#{ File::basename(@shell) }__"], '-l'
|
44
|
+
end
|
45
|
+
rescue Exception => e
|
46
|
+
STDERR.puts(Util::errmsg(e))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
@r.close
|
50
|
+
#}}}
|
51
|
+
end
|
52
|
+
def run
|
53
|
+
#{{{
|
54
|
+
@w.puts @command
|
55
|
+
@w.close
|
56
|
+
#}}}
|
57
|
+
end
|
58
|
+
#}}}
|
59
|
+
end # class JobRunner
|
60
|
+
#}}}
|
61
|
+
end # module RQ
|
62
|
+
$__rq_jobrunner__ = __FILE__
|
63
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
unless defined? $__rq_jobrunnerdaemon__
|
2
|
+
module RQ
|
3
|
+
#{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require 'drb/drb'
|
8
|
+
require 'fileutils'
|
9
|
+
require 'tmpdir'
|
10
|
+
require 'tempfile'
|
11
|
+
|
12
|
+
require LIBDIR + 'job'
|
13
|
+
require LIBDIR + 'jobrunner'
|
14
|
+
|
15
|
+
class JobRunnerDaemon
|
16
|
+
#{{{
|
17
|
+
include Logging
|
18
|
+
|
19
|
+
class << self
|
20
|
+
#{{{
|
21
|
+
def daemon(*a,&b)
|
22
|
+
#{{{
|
23
|
+
jrd = new(*a, &b)
|
24
|
+
|
25
|
+
r, w = IO::pipe
|
26
|
+
|
27
|
+
unless((pid = fork)) # child
|
28
|
+
$0 = "#{ self }".gsub(%r/[^a-zA-Z]+/,'_').downcase
|
29
|
+
begin
|
30
|
+
r.close
|
31
|
+
n = 0
|
32
|
+
uri = nil
|
33
|
+
socket = nil
|
34
|
+
|
35
|
+
42.times do
|
36
|
+
begin
|
37
|
+
s = "%s/%s_%s_%s_%s" %
|
38
|
+
[Dir::tmpdir, File::basename($0), Process::ppid, n, rand(42)]
|
39
|
+
u = "drbunix://#{ s }"
|
40
|
+
DRb::start_service u, jrd
|
41
|
+
socket = s
|
42
|
+
uri = u
|
43
|
+
rescue Errno::EADDRINUSE
|
44
|
+
n += 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if socket and uri
|
49
|
+
w.write socket
|
50
|
+
w.close
|
51
|
+
pid = Process::pid
|
52
|
+
ppid = Process::ppid
|
53
|
+
cur = Thread::current
|
54
|
+
Thread::new(pid, ppid, cur) do |pid, ppid, cur|
|
55
|
+
loop do
|
56
|
+
begin
|
57
|
+
Process::kill 0, ppid
|
58
|
+
sleep 42
|
59
|
+
rescue
|
60
|
+
cur.raise "parent <#{ ppid }> died unexpectedly"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
DRb::thread.join
|
65
|
+
else
|
66
|
+
w.close
|
67
|
+
end
|
68
|
+
ensure
|
69
|
+
exit!
|
70
|
+
end
|
71
|
+
else # parent
|
72
|
+
w.close
|
73
|
+
socket = r.read
|
74
|
+
r.close
|
75
|
+
|
76
|
+
if socket and File::exist?(socket)
|
77
|
+
at_exit{ FileUtils::rm_f socket }
|
78
|
+
uri = "drbunix://#{ socket }"
|
79
|
+
DRb::start_service 'druby://localhost:0', nil
|
80
|
+
jrd = DRbObject::new nil, uri
|
81
|
+
jrd.pid = pid
|
82
|
+
jrd.uri = uri
|
83
|
+
else
|
84
|
+
raise "failed to start job runner daemon"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
return jrd
|
89
|
+
#}}}
|
90
|
+
end
|
91
|
+
#}}}
|
92
|
+
end
|
93
|
+
attr :runners
|
94
|
+
attr :pid, true
|
95
|
+
attr :uri, true
|
96
|
+
def initialize
|
97
|
+
#{{{
|
98
|
+
@runners = {}
|
99
|
+
@uri = nil
|
100
|
+
@pid = Process::pid
|
101
|
+
#}}}
|
102
|
+
end
|
103
|
+
def runner job
|
104
|
+
#{{{
|
105
|
+
r = nil
|
106
|
+
retried = false
|
107
|
+
begin
|
108
|
+
r = JobRunner::new job
|
109
|
+
rescue Errno::ENOMEM, Errno::EAGAIN
|
110
|
+
GC::start
|
111
|
+
unless retried
|
112
|
+
retried = true
|
113
|
+
retry
|
114
|
+
else
|
115
|
+
raise
|
116
|
+
end
|
117
|
+
end
|
118
|
+
@runners[r.pid] = r
|
119
|
+
r
|
120
|
+
#}}}
|
121
|
+
end
|
122
|
+
def wait
|
123
|
+
#{{{
|
124
|
+
pid = Process::wait
|
125
|
+
@runners.delete pid
|
126
|
+
pid
|
127
|
+
#}}}
|
128
|
+
end
|
129
|
+
def wait2
|
130
|
+
#{{{
|
131
|
+
pid, status = Process::wait2
|
132
|
+
@runners.delete pid
|
133
|
+
[pid, status]
|
134
|
+
#}}}
|
135
|
+
end
|
136
|
+
def waitpid pid = -1, flags = 0
|
137
|
+
#{{{
|
138
|
+
pid = pid.pid if pid.respond_to? 'pid'
|
139
|
+
pid = Process::waitpid pid, flags
|
140
|
+
@runners.delete pid
|
141
|
+
pid
|
142
|
+
#}}}
|
143
|
+
end
|
144
|
+
def waitpid2 pid = -1, flags = 0
|
145
|
+
#{{{
|
146
|
+
pid = pid.pid if pid.respond_to? 'pid'
|
147
|
+
pid, status = Process::waitpid2 pid, flags
|
148
|
+
@runners.delete pid
|
149
|
+
[pid, status]
|
150
|
+
#}}}
|
151
|
+
end
|
152
|
+
def shutdown
|
153
|
+
#{{{
|
154
|
+
@death =
|
155
|
+
Thread::new do
|
156
|
+
begin
|
157
|
+
while not @runners.empty?
|
158
|
+
pid = Process::wait
|
159
|
+
@runners.delete pid
|
160
|
+
end
|
161
|
+
ensure
|
162
|
+
sleep 4.2
|
163
|
+
DRb::thread.kill
|
164
|
+
Thread::main exit!
|
165
|
+
end
|
166
|
+
end
|
167
|
+
#}}}
|
168
|
+
end
|
169
|
+
def install_signal_handlers
|
170
|
+
#{{{
|
171
|
+
%w(TERM INT HUP).each{|sig| trap sig, 'SIG_IGN'}
|
172
|
+
#}}}
|
173
|
+
end
|
174
|
+
#}}}
|
175
|
+
end # class JobRunnerDaemon
|
176
|
+
#}}}
|
177
|
+
end # module RQ
|
178
|
+
$__rq_jobrunnerdaemon__ = __FILE__
|
179
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
unless defined? $__rq_lister__
|
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 Lister < MainHelper
|
10
|
+
#{{{
|
11
|
+
def list
|
12
|
+
#{{{
|
13
|
+
set_q
|
14
|
+
@q.list(*@argv)
|
15
|
+
#}}}
|
16
|
+
end
|
17
|
+
#}}}
|
18
|
+
end # class Lister
|
19
|
+
#}}}
|
20
|
+
end # module RQ
|
21
|
+
$__rq_lister__ = __FILE__
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
unless defined? $__rq_locker__
|
2
|
+
module RQ
|
3
|
+
#{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require LIBDIR + 'util'
|
8
|
+
require LIBDIR + 'locker'
|
9
|
+
|
10
|
+
class Locker < MainHelper
|
11
|
+
#{{{
|
12
|
+
def lock
|
13
|
+
#{{{
|
14
|
+
set_q
|
15
|
+
ltype = @argv.shift
|
16
|
+
debug{ "ltype <#{ ltype }>" }
|
17
|
+
read_only =
|
18
|
+
case ltype
|
19
|
+
when /^\s*r(?:ead)?|^\s*sh(?:ared)?/io
|
20
|
+
true
|
21
|
+
when /^\s*w(?:rite)?|^\s*ex(?:clusive)?/io
|
22
|
+
false
|
23
|
+
else
|
24
|
+
raise "lock type must be one of (r)ead|(sh)ared|(w)rite|(ex)clusive, not <#{ ltype }>"
|
25
|
+
end
|
26
|
+
cmd = @argv.join(' ').strip
|
27
|
+
raise "no command given for lock type <#{ ltype }>" if cmd.empty?
|
28
|
+
debug{ "cmd <#{ cmd }>" }
|
29
|
+
@q.lock(:read_only => read_only){ Util::system cmd }
|
30
|
+
#}}}
|
31
|
+
end
|
32
|
+
#}}}
|
33
|
+
end # class Locker
|
34
|
+
#}}}
|
35
|
+
end # module RQ
|
36
|
+
$__rq_locker__ = __FILE__
|
37
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
unless defined? $__rq_logging__
|
2
|
+
module RQ
|
3
|
+
#{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require "logger"
|
8
|
+
|
9
|
+
require LIBDIR + 'util'
|
10
|
+
#
|
11
|
+
# module which adds logging methods to classes
|
12
|
+
#
|
13
|
+
module Logging
|
14
|
+
#{{{
|
15
|
+
#
|
16
|
+
# a module that adds an accessor to Logging objects in ored to fix a bug where
|
17
|
+
# not all logging devices are put into sync mode, resulting in improper log
|
18
|
+
# rolling. this is a hack.
|
19
|
+
#
|
20
|
+
module LoggerExt
|
21
|
+
#{{{
|
22
|
+
attr :logdev
|
23
|
+
#}}}
|
24
|
+
end # module LoggerExt
|
25
|
+
#
|
26
|
+
# implementations of the methods shared by both classes and objects of classes
|
27
|
+
# which include Logging
|
28
|
+
#
|
29
|
+
module LogMethods
|
30
|
+
#{{{
|
31
|
+
def logger
|
32
|
+
#{{{
|
33
|
+
if defined?(@logger) and @logger
|
34
|
+
@logger
|
35
|
+
else
|
36
|
+
if Class === self
|
37
|
+
@logger = self.default_logger
|
38
|
+
else
|
39
|
+
@logger = self::class::logger
|
40
|
+
end
|
41
|
+
raise "@logger is undefined!" unless defined?(@logger) and @logger
|
42
|
+
@logger
|
43
|
+
end
|
44
|
+
#}}}
|
45
|
+
end
|
46
|
+
def logger= log
|
47
|
+
#{{{
|
48
|
+
@logger = log
|
49
|
+
@logger.extend LoggerExt
|
50
|
+
@logger.logdev.dev.sync = true
|
51
|
+
@logger
|
52
|
+
#}}}
|
53
|
+
end
|
54
|
+
def debug(*args, &block); logger.debug(*args, &block); end
|
55
|
+
def info(*args, &block); logger.info(*args, &block) ; end
|
56
|
+
def warn(*args, &block); logger.warn(*args, &block) ; end
|
57
|
+
def error(*args, &block); logger.error(*args, &block); end
|
58
|
+
def fatal(*args, &block); logger.fatal(*args, &block); end
|
59
|
+
def logerr e
|
60
|
+
#{{{
|
61
|
+
if logger.debug?
|
62
|
+
error{ Util::errmsg e }
|
63
|
+
else
|
64
|
+
error{ Util::emsg e }
|
65
|
+
end
|
66
|
+
#}}}
|
67
|
+
end
|
68
|
+
#}}}
|
69
|
+
end # module LogMethods
|
70
|
+
EOL = "\n"
|
71
|
+
DIV0 = ("." * 79) << EOL
|
72
|
+
DIV1 = ("-" * 79) << EOL
|
73
|
+
DIV2 = ("=" * 79) << EOL
|
74
|
+
DIV3 = ("#" * 79) << EOL
|
75
|
+
SEC0 = ("." * 16) << EOL
|
76
|
+
SEC1 = ("-" * 16) << EOL
|
77
|
+
SEC2 = ("=" * 16) << EOL
|
78
|
+
SEC3 = ("#" * 16) << EOL
|
79
|
+
class << self
|
80
|
+
#{{{
|
81
|
+
def append_features c
|
82
|
+
#{{{
|
83
|
+
ret = super
|
84
|
+
c.extend LogMethods
|
85
|
+
class << c
|
86
|
+
def default_logger
|
87
|
+
#{{{
|
88
|
+
if defined?(@default_logger) and @default_logger
|
89
|
+
@default_logger
|
90
|
+
else
|
91
|
+
self.default_logger = Logger.new STDOUT
|
92
|
+
@default_logger.debug{ "<#{ self }> using default logger"}
|
93
|
+
@default_logger
|
94
|
+
end
|
95
|
+
#}}}
|
96
|
+
end
|
97
|
+
def default_logger= log
|
98
|
+
#{{{
|
99
|
+
@default_logger = log
|
100
|
+
@default_logger.extend LoggerExt
|
101
|
+
@default_logger.logdev.dev.sync = true
|
102
|
+
@default_logger
|
103
|
+
#}}}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
ret
|
107
|
+
#}}}
|
108
|
+
end
|
109
|
+
#}}}
|
110
|
+
end
|
111
|
+
include LogMethods
|
112
|
+
#}}}
|
113
|
+
end # module Logging
|
114
|
+
#}}}
|
115
|
+
end # module rq
|
116
|
+
$__rq_logging__ = __FILE__
|
117
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
unless defined? $__rq_mainhelper__
|
2
|
+
module RQ
|
3
|
+
#{{{
|
4
|
+
LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
|
5
|
+
defined? LIBDIR
|
6
|
+
|
7
|
+
require LIBDIR + 'util'
|
8
|
+
require LIBDIR + 'logging'
|
9
|
+
|
10
|
+
class MainHelper
|
11
|
+
#{{{
|
12
|
+
include Util
|
13
|
+
include Logging
|
14
|
+
attr :main
|
15
|
+
attr :logger
|
16
|
+
attr :argv
|
17
|
+
attr :env
|
18
|
+
attr :cmd
|
19
|
+
attr :options
|
20
|
+
attr :qpath
|
21
|
+
attr :mode
|
22
|
+
attr :q
|
23
|
+
def initialize main
|
24
|
+
#{{{
|
25
|
+
@main = main
|
26
|
+
@logger = main.logger
|
27
|
+
@argv = main.argv
|
28
|
+
@env = main.env
|
29
|
+
@cmd = main.cmd
|
30
|
+
@options = main.options
|
31
|
+
@qpath = main.qpath
|
32
|
+
@mode = main.mode
|
33
|
+
@q = nil
|
34
|
+
#}}}
|
35
|
+
end
|
36
|
+
def set_q
|
37
|
+
#{{{
|
38
|
+
raise "q <#{ @qpath }> does not exist" unless test ?d, @qpath
|
39
|
+
@q = JobQueue::new @qpath, 'logger' => @logger
|
40
|
+
if @options['snapshot']
|
41
|
+
ss = "#{ $0 }_#{ Process::pid }_#{ Thread::current.id.abs }_#{ rand Time::now.to_i }".gsub(%r|/|o,'_')
|
42
|
+
qtmp = File::join Dir::tmpdir, ss
|
43
|
+
@q = @q.snapshot qtmp, @options['retries']
|
44
|
+
at_exit{ FileUtils::rm_rf qtmp }
|
45
|
+
end
|
46
|
+
#}}}
|
47
|
+
end
|
48
|
+
#}}}
|
49
|
+
end # class MainHelper
|
50
|
+
#}}}
|
51
|
+
end # module RQ
|
52
|
+
$__rq_mainhelper__ = __FILE__
|
53
|
+
end
|