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.
Files changed (67) hide show
  1. data/Gemfile +22 -0
  2. data/Gemfile.lock +22 -0
  3. data/INSTALL +166 -0
  4. data/LICENSE +10 -0
  5. data/Makefile +6 -0
  6. data/README +1183 -0
  7. data/Rakefile +37 -0
  8. data/TODO +24 -0
  9. data/TUTORIAL +230 -0
  10. data/VERSION +1 -0
  11. data/bin/rq +902 -0
  12. data/bin/rqmailer +865 -0
  13. data/example/a.rb +7 -0
  14. data/extconf.rb +198 -0
  15. data/gemspec.rb +40 -0
  16. data/install.rb +210 -0
  17. data/lib/rq.rb +155 -0
  18. data/lib/rq/arrayfields.rb +371 -0
  19. data/lib/rq/backer.rb +31 -0
  20. data/lib/rq/configfile.rb +82 -0
  21. data/lib/rq/configurator.rb +40 -0
  22. data/lib/rq/creator.rb +54 -0
  23. data/lib/rq/cron.rb +144 -0
  24. data/lib/rq/defaultconfig.txt +5 -0
  25. data/lib/rq/deleter.rb +51 -0
  26. data/lib/rq/executor.rb +40 -0
  27. data/lib/rq/feeder.rb +527 -0
  28. data/lib/rq/ioviewer.rb +48 -0
  29. data/lib/rq/job.rb +51 -0
  30. data/lib/rq/jobqueue.rb +947 -0
  31. data/lib/rq/jobrunner.rb +110 -0
  32. data/lib/rq/jobrunnerdaemon.rb +193 -0
  33. data/lib/rq/lister.rb +47 -0
  34. data/lib/rq/locker.rb +43 -0
  35. data/lib/rq/lockfile.rb +564 -0
  36. data/lib/rq/logging.rb +124 -0
  37. data/lib/rq/mainhelper.rb +189 -0
  38. data/lib/rq/orderedautohash.rb +39 -0
  39. data/lib/rq/orderedhash.rb +240 -0
  40. data/lib/rq/qdb.rb +733 -0
  41. data/lib/rq/querier.rb +98 -0
  42. data/lib/rq/rails.rb +80 -0
  43. data/lib/rq/recoverer.rb +28 -0
  44. data/lib/rq/refresher.rb +80 -0
  45. data/lib/rq/relayer.rb +283 -0
  46. data/lib/rq/resource.rb +22 -0
  47. data/lib/rq/resourcemanager.rb +40 -0
  48. data/lib/rq/resubmitter.rb +100 -0
  49. data/lib/rq/rotater.rb +98 -0
  50. data/lib/rq/sleepcycle.rb +46 -0
  51. data/lib/rq/snapshotter.rb +40 -0
  52. data/lib/rq/sqlite.rb +286 -0
  53. data/lib/rq/statuslister.rb +48 -0
  54. data/lib/rq/submitter.rb +113 -0
  55. data/lib/rq/toucher.rb +182 -0
  56. data/lib/rq/updater.rb +94 -0
  57. data/lib/rq/usage.rb +1222 -0
  58. data/lib/rq/util.rb +304 -0
  59. data/rdoc.sh +17 -0
  60. data/rq-ruby1.8.gemspec +120 -0
  61. data/test/.gitignore +1 -0
  62. data/test/test_rq.rb +145 -0
  63. data/white_box/crontab +2 -0
  64. data/white_box/joblist +8 -0
  65. data/white_box/killrq +18 -0
  66. data/white_box/rq_killer +27 -0
  67. metadata +208 -0
@@ -0,0 +1,48 @@
1
+ unless defined? $__rq_statuslister__
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
+ # the StatusLister class dumps a yaml report on stdout showing how many jobs
11
+ # are in each of the states
12
+ # * pending
13
+ # * holding
14
+ # * running
15
+ # * finished
16
+ # * dead
17
+ #
18
+ class StatusLister < MainHelper
19
+ #--{{{
20
+ def statuslist
21
+ #--{{{
22
+ set_q
23
+ exit_code_map = parse_exit_code_map @options['exit']
24
+ puts @q.status('exit_code_map' => exit_code_map).to_yaml
25
+ #--}}}
26
+ end
27
+ def parse_exit_code_map emap = 'ok=42'
28
+ emap ||= 'ok=42'
29
+ map = {}
30
+ begin
31
+ tokens = emap.strip.gsub(%r/\s+/, ' ').gsub(%r/\s*=\s*/, '=').split
32
+ tokens.each do |token|
33
+ key, *values = token.split %r/[=,]/
34
+ values.map!{|value| Integer value}
35
+ map[key.to_s] = values
36
+ end
37
+ rescue => e
38
+ warn{ e }
39
+ raise "bad map <#{ emap }"
40
+ end
41
+ map
42
+ end
43
+ #--}}}
44
+ end # class StatusLister
45
+ #--}}}
46
+ end # module RQ
47
+ $__rq_statuslister__ = __FILE__
48
+ end
@@ -0,0 +1,113 @@
1
+ unless defined? $__rq_submitter__
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
+
10
+ #
11
+ # the Submitter class is responsible for submitting commands to the queue,
12
+ # the commands it submits are taken from the command line, stdin, or the
13
+ # specified infile. the format of commands read from stdin or file is
14
+ # either a simple list of commands, one per line, where blank lines are
15
+ # ignored OR it is valid yaml input. if the Submitter sees the token
16
+ # '---' in the input stream it is assumed the input is yaml. for an
17
+ # example of valid yaml input examine the output of a Lister using
18
+ #
19
+ # rq q list
20
+ #
21
+ # the output of other commands, such as that of a Querier may also be used
22
+ # as input to submit
23
+ #
24
+ class Submitter < MainHelper
25
+ #--{{{
26
+ def submit
27
+ #--{{{
28
+ set_q
29
+
30
+ @priority = @options['priority']
31
+ debug{ "priority <#{ @priority }>" }
32
+
33
+ @tag = @options['tag']
34
+ debug{ "tag <#{ @tag }>" }
35
+
36
+ @runner = @options['runner']
37
+ debug{ "runner <#{ @runner }>" }
38
+
39
+ @restartable = @options['restartable']
40
+ debug{ "restartable <#{ @restartable }>" }
41
+
42
+ @infile = @options['infile']
43
+ debug{ "infile <#{ @infile }>" }
44
+
45
+ @job_stdin = @options['stdin']
46
+ debug{ "job_stdin <#{ @job_stdin }>" }
47
+
48
+ @stage = @options['stage']
49
+ debug{ "stage <#{ @stage }>" }
50
+
51
+ @data = @options['data']
52
+ debug{ "data <#{ @data }>" }
53
+
54
+ if job_stdin == '-' and stdin?
55
+ abort "cannot specify both jobs and job input on stdin"
56
+ end
57
+
58
+ jobs = []
59
+
60
+ unless @argv.empty?
61
+ job = Job::new
62
+ job['command'] = @argv.join(' ')
63
+ job['priority'] = @priority
64
+ job['tag'] = @tag
65
+ job['runner'] = @runner
66
+ job['restartable'] = @restartable
67
+ jobs << job
68
+ end
69
+
70
+ if @infile
71
+ open(@infile) do |f|
72
+ debug{ "reading jobs from <#{ @infile }>" }
73
+ loadio f, @infile, jobs
74
+ end
75
+ end
76
+
77
+ if jobs.empty? and stdin?
78
+ debug{ "reading jobs from <stdin>" }
79
+ loadio stdin, 'stdin', jobs
80
+ end
81
+
82
+ abort "no jobs specified!" if jobs.empty?
83
+
84
+ init_job_stdin!
85
+
86
+ state = @stage ? 'holding' : 'pending'
87
+
88
+ jobs.each do |job|
89
+ job['state'] = state
90
+ job['priority'] = @priority if @options.has_key?('priority')
91
+ job['tag'] = @tag if @options.has_key?('tag')
92
+ job['runner'] = @runner if @options.has_key?('runner')
93
+ job['restartable'] = @restartable if @options.has_key?('restartable')
94
+ job['stdin'] = @job_stdin if @job_stdin
95
+ job['data'] = @data if @data
96
+ end
97
+
98
+ if @options['quiet']
99
+ @q.submit(*jobs)
100
+ else
101
+ @q.submit(*jobs, &dumping_yaml_tuples)
102
+ end
103
+
104
+ jobs = nil
105
+ self
106
+ #--}}}
107
+ end
108
+ #--}}}
109
+ end # class Submitter
110
+ #--}}}
111
+ end # module RQ
112
+ $__rq_submitter__ = __FILE__
113
+ end
@@ -0,0 +1,182 @@
1
+ unless defined? $__rq_toucher__
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
+
10
+ #
11
+ # nodoc
12
+ #
13
+ class Toucher < MainHelper
14
+ #--{{{
15
+ def touch
16
+ #--{{{
17
+ set_q
18
+
19
+ @priority = @options['priority']
20
+ debug{ "priority <#{ @priority }>" }
21
+
22
+ @tag = @options['tag']
23
+ debug{ "tag <#{ @tag }>" }
24
+
25
+ @runner = @options['runner']
26
+ debug{ "runner <#{ @runner }>" }
27
+
28
+ @restartable = @options['restartable']
29
+ debug{ "restartable <#{ @restartable }>" }
30
+
31
+ @infile = @options['infile']
32
+ debug{ "infile <#{ @infile }>" }
33
+
34
+ @job_stdin = @options['stdin']
35
+ debug{ "job_stdin <#{ @job_stdin }>" }
36
+
37
+ @stage = @options['stage']
38
+ debug{ "stage <#{ @stage }>" }
39
+
40
+ @data = @options['data']
41
+ debug{ "data <#{ @data }>" }
42
+
43
+ if job_stdin == '-' and stdin?
44
+ abort "cannot specify both jobs and job input on stdin"
45
+ end
46
+
47
+ jobs = []
48
+
49
+ unless @argv.empty?
50
+ job = Job::new
51
+ job['command'] = @argv.join(' ')
52
+ job['priority'] = @priority
53
+ job['tag'] = @tag
54
+ job['runner'] = @runner
55
+ job['restartable'] = @restartable
56
+ job['data'] = @data
57
+ jobs << job
58
+ end
59
+
60
+ if @infile
61
+ open(@infile) do |f|
62
+ debug{ "reading jobs from <#{ @infile }>" }
63
+ loadio f, @infile, jobs
64
+ end
65
+ end
66
+
67
+ if jobs.empty? and stdin?
68
+ debug{ "reading jobs from <stdin>" }
69
+ loadio stdin, 'stdin', jobs
70
+ end
71
+
72
+ abort "no jobs specified!" if jobs.empty?
73
+
74
+ init_job_stdin!
75
+
76
+ state = @stage ? 'holding' : 'pending'
77
+
78
+ jobs.each do |job|
79
+ job['state'] = state
80
+ job['priority'] = @priority if @options.has_key?('priority')
81
+ job['tag'] = @tag if @options.has_key?('tag')
82
+ job['runner'] = @runner if @options.has_key?('runner')
83
+ job['restartable'] = @restartable if @options.has_key?('restartable')
84
+ job['stdin'] = @job_stdin if @job_stdin
85
+ job['data'] = @data if @data
86
+ end
87
+
88
+ #
89
+ # state + lambdas for submit process...
90
+ #
91
+
92
+ list = []
93
+
94
+ tmpfile =
95
+ lambda do |basename|
96
+ basename = File.basename basename.to_s
97
+ Tempfile.new "#{ basename }_#{ Process.pid }_#{ rand.to_s }"
98
+ end
99
+
100
+ update_job =
101
+ lambda do |pjob, ujob|
102
+ kvs, jid = {}, pjob['jid']
103
+ # handle stdin
104
+ pstdin, ustdin = pjob['stdin'], ujob['stdin']
105
+ if pstdin || ustdin
106
+ pbuf =
107
+ if pstdin
108
+ pstdin = @q.standard_in_4 jid
109
+ IO.read pstdin if test ?e, pstdin
110
+ end
111
+ ubuf =
112
+ if ustdin
113
+ IO.read ustdin if test ?e, ustdin
114
+ end
115
+ #y 'pbuf' => pbuf
116
+ #y 'ubuf' => ubuf
117
+ f = ustdin ? open(ustdin,'w') : tmpfile[ustdin]
118
+ begin
119
+ f.write pbuf if pbuf
120
+ f.write ubuf if pbuf
121
+ ensure
122
+ f.close
123
+ end
124
+ kvs['stdin'] = ujob['stdin'] = f.path
125
+ #y 'stdin' => ujob['stdin']
126
+ end
127
+ # handle other keys
128
+ allowed = %w( priority runner restartable )
129
+ allowed.each do |key|
130
+ val = ujob[key]
131
+ kvs[key] = val if val
132
+ end
133
+ @q.update(kvs, jid){|updated| list << updated}
134
+ end
135
+
136
+ submit_job =
137
+ lambda do |job|
138
+ @q.submit(job){|submitted| list << submitted}
139
+ end
140
+
141
+
142
+ #
143
+ # update or submit
144
+ #
145
+ @q.transaction do
146
+ pending = @q.list 'pending'
147
+
148
+ pjobs, pcommands = {}, {}
149
+
150
+ pending.each do |job|
151
+ jid = job['jid']
152
+ command = job['command'].strip
153
+ tag = job['tag'].to_s.strip
154
+ pjobs[jid] = job
155
+ pcommands[[command, tag]] = jid
156
+ end
157
+
158
+ jobs.each do |job|
159
+ jid = job['jid']
160
+ command = job['command'].strip
161
+ tag = job['tag'].to_s.strip
162
+ if((jid = pcommands[[command, tag]]))
163
+ update_job[ pjobs[jid], job ]
164
+ else
165
+ submit_job[ job ]
166
+ end
167
+ end
168
+ end
169
+
170
+ list.each &dumping_yaml_tuples unless @options['quiet']
171
+
172
+ jobs = nil
173
+ list = nil
174
+ self
175
+ #--}}}
176
+ end
177
+ #--}}}
178
+ end # class Toucher
179
+ #--}}}
180
+ end # module RQ
181
+ $__rq_toucher__ = __FILE__
182
+ end
@@ -0,0 +1,94 @@
1
+ unless defined? $__rq_updater__
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
+ # the Updater class reads jids from the command line and then looks for
11
+ # key=value pairs on the command line, stdin, or from infile. the jids are
12
+ # taken to be jids to update with the key=values pairs scanned
13
+ #
14
+ class Updater < MainHelper
15
+ #--{{{
16
+ def update
17
+ #--{{{
18
+ set_q
19
+ jids = []
20
+ kvs = {}
21
+
22
+ kvs.update "stdin" => job_stdin if job_stdin?
23
+
24
+ #
25
+ # scan argv for jids to update
26
+ #
27
+ list, @argv = @argv.partition{|arg| arg =~ %r/^\s*(?:jid\s*=\s*)?\d+\s*$/}
28
+ list.each{|elem| jids << Integer(elem[%r/\d+/])}
29
+ list, @argv = @argv.partition{|arg| arg =~ %r/^\s*(?:p(?:ending)|h(?:olding))\s*$/}
30
+ list.each{|elem| jids << elem.strip.downcase}
31
+ #
32
+ # scan argv for key=val pairs
33
+ #
34
+ keyeqpat = %r/\s*([^\s=]+)\s*=\s*([^\s]*)\s*$/
35
+ list, @argv = @argv.partition{|arg| arg =~ keyeqpat}
36
+ list.each do |elem|
37
+ m = elem.match(keyeqpat)
38
+ k, v = m[1], m[2]
39
+ k = (k.empty? ? nil : k.strip)
40
+ v = (v.empty? ? nil : v.strip)
41
+ v =
42
+ case v
43
+ when %r/^\s*(?:nil|null?)\s*$/io
44
+ nil
45
+ else
46
+ v
47
+ end
48
+ kvs[k] = v
49
+ end
50
+
51
+ unless @argv.empty?
52
+ raise "don't know what to do with crap arguments <#{ @argv.join ' ' }>"
53
+ end
54
+
55
+ #
56
+ # scan stdin for jids to update iff in pipeline
57
+ #
58
+ if stdin?
59
+ #pat = %r/^(?:\s*jid\s*:)?\s*(\d+)\s*$/io
60
+ while((line = stdin.gets))
61
+ case line
62
+ when %r/^(?:\s*jid\s*:)?\s*(\d+)\s*$/io
63
+ jids << Integer($1)
64
+ when %r/^\s*p(?:ending)\s*$/io
65
+ jids << 'pending'
66
+ when %r/^\s*h(?:olding)\s*$/io
67
+ jids << 'holding'
68
+ else
69
+ next
70
+ end
71
+ end
72
+ end
73
+ #jids.map!{|jid| jid =~ %r/^\s*\d+\s*$/o ? Integer(jid) : jid}
74
+ #raise "no jids" if jids.empty?
75
+ #
76
+ # if no jids were specified simply update ALL pending and holding jobs
77
+ #
78
+ jids << 'pending' << 'holding' if jids.empty?
79
+ #
80
+ # apply the update
81
+ #
82
+ if @options['quiet']
83
+ @q.update(kvs,*jids)
84
+ else
85
+ @q.update(kvs,*jids, &dumping_yaml_tuples)
86
+ end
87
+ #--}}}
88
+ end
89
+ #--}}}
90
+ end # class Updater
91
+ #--}}}
92
+ end # module RQ
93
+ $__rq_updater__ = __FILE__
94
+ end
@@ -0,0 +1,1222 @@
1
+ unless defined? $__rq_usage__
2
+ module RQ
3
+ #--{{{
4
+ LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
5
+ defined? LIBDIR
6
+
7
+ require LIBDIR + 'util'
8
+
9
+ #
10
+ # the reasons this is pulled off into it's own module are
11
+ # * it's really big
12
+ # * it totally wrecks vim's syntax highlighting
13
+ #
14
+ module Usage
15
+ #--{{{
16
+ def cget const
17
+ #--{{{
18
+ begin
19
+ klass::const_get const
20
+ rescue NameError
21
+ nil
22
+ end
23
+ #--}}}
24
+ end
25
+ def usage opts = {}
26
+ #--{{{
27
+ port = getopt 'port', opts
28
+ long = getopt 'long', opts
29
+
30
+ port = STDERR if port.nil?
31
+
32
+ if(long and (txt = cget 'USAGE'))
33
+ port << txt << "\n"
34
+ elsif((txt = cget 'USAGE_BANNER'))
35
+ port << txt << "\n"
36
+ else
37
+ port << "#{ $0 } [options]* [args]*" << "\n"
38
+ end
39
+
40
+ if((optspec = cget 'OPTSPEC'))
41
+ port << 'OPTIONS' << "\n"
42
+ optspec.each do |os|
43
+ a, b, c = os
44
+ long, short, desc = nil
45
+ [a,b,c].each do |word|
46
+ next unless word
47
+ word.strip!
48
+ case word
49
+ when %r/^--[^-]/o
50
+ long = word
51
+ when %r/^-[^-]/o
52
+ short = word
53
+ else
54
+ desc = word
55
+ end
56
+ end
57
+ spec = ((long and short) ? [long, short] : [long])
58
+ if spec
59
+ port << columnize(spec.join(', '), 80, 2)
60
+ port << "\n"
61
+ end
62
+ if desc
63
+ port << columnize(desc, 80, 8)
64
+ port << "\n"
65
+ end
66
+ end
67
+ port << "\n"
68
+ end
69
+
70
+ if((txt = cget 'EXAMPLES'))
71
+ port << txt << "\n"
72
+ end
73
+
74
+ port
75
+ #--}}}
76
+ end
77
+ module_function :usage
78
+ public :usage
79
+
80
+ PROGNAM = 'rq'
81
+
82
+ # :nodoc
83
+ USAGE_BANNER =
84
+ #--{{{
85
+ <<-usage_banner
86
+ NAME
87
+
88
+ rq v#{ VERSION }
89
+
90
+ SYNOPSIS
91
+
92
+ rq (queue | export RQ_Q=q) mode [mode_args]* [options]*
93
+
94
+ usage_banner
95
+ #--}}}
96
+
97
+ # :nodoc
98
+ USAGE =
99
+ #--{{{
100
+ <<-usage
101
+ #{ USAGE_BANNER }
102
+ URIS
103
+
104
+ #{ WEBSITE } - main website
105
+ http://www.linuxjournal.com/article/7922
106
+
107
+ and
108
+
109
+ http://rubyforge.org/projects/codeforpeople/
110
+ http://codeforpeople.com/lib/ruby/rq/
111
+
112
+ LICENSE
113
+
114
+ rq is distributed under the BSD license, see the ./LICENSE file
115
+
116
+ INSTALL
117
+
118
+ See the ./INSTALL file, but quickly
119
+
120
+ gems (per node):
121
+
122
+ gem >=3.4.3:
123
+
124
+ - install sqlite2 (Debian apt-get install libsqlite0-dev)
125
+ - wget http://rubyforge.org/frs/download.php/1070/sqlite-1.3.1.gem
126
+ - gem1.8 install sqlite-1.3.1.gem
127
+ - gem1.8 install posixlock
128
+ - gem1.8 install arrayfields
129
+ - gem1.8 install lockfile
130
+ - gem1.8 install rq-ruby1.8 (or run from source)
131
+
132
+ Also available from http://bio4.dnsalias.net/download/gem/ruby1.8/
133
+
134
+ manual (cluster wide):
135
+
136
+ (note, this procedure is out of date and breaks on gcc 4.4 and later)
137
+ - download latest release from http://codeforpeople.com/lib/ruby/rq/
138
+ - tar xvfz rq-X.X.X.tgz
139
+ - cd rq-X-X-X
140
+ - cd all
141
+ - ./install.sh /full/path/to/nfs/mounted/directory/
142
+
143
+ Debian flavours:
144
+
145
+ see ./INSTALL file for latest
146
+
147
+ DESCRIPTION
148
+
149
+ ruby queue (rq) is a zero-admin zero-configuration tool used to create instant
150
+ unix clusters. rq requires only a central nfs filesystem in order to manage a
151
+ simple sqlite database as a distributed priority work queue. this simple
152
+ design allows researchers with minimal unix experience to install and
153
+ configure, in only a few minutes and without root privileges, a robust unix
154
+ cluster capable of distributing processes to many nodes - bringing dozens of
155
+ powerful cpus to their knees with a single blow. clearly this software should
156
+ be kept out of the hands of free radicals, seti enthusiasts, and one mr. j
157
+ safran.
158
+
159
+ the central concept of rq is that n nodes work in isolation to pull jobs
160
+ from an centrally mounted nfs priority work queue in a synchronized fashion.
161
+ the nodes have absolutely no knowledge of each other and all communication
162
+ is done via the queue meaning that, so long as the queue is available via
163
+ nfs and a single node is running jobs from it, the system will continue to
164
+ process jobs. there is no centralized process whatsoever - all nodes work
165
+ to take jobs from the queue and run them as fast as possible. this creates
166
+ a system which load balances automatically and is robust in face of node
167
+ failures.
168
+
169
+ although the rq system is simple in it's design it features powerful
170
+ functionality such as priority management, predicate and sql query, compact
171
+ streaming command-line processing, programmable api, hot-backup, and
172
+ input/capture of the stdin/stdout/stderr io streams of remote jobs. to date
173
+ rq has had no reported runtime failures and is in operation at
174
+ dozens of research centers around the world. while rq is written in
175
+ the Ruby programming language, there is no Ruby programming
176
+ involved in using rq.
177
+
178
+ INVOCATION
179
+
180
+ the first argument to any rq command is the always the name of the queue
181
+ while the second is the mode of operation. the queue name may be omitted
182
+ if, and only if, the environment variable RQ_Q has been set to contain the
183
+ absolute path of target queue.
184
+
185
+ for instance, the command
186
+
187
+ ~ > rq queue list
188
+
189
+ is equivalent to
190
+
191
+ ~ > export RQ_Q=queue
192
+ ~ > rq list
193
+
194
+ this facility can be used to create aliases for several queues, for example,
195
+ a .bashrc containing
196
+
197
+ alias MYQ="RQ_Q=/path/to/myq rq"
198
+
199
+ alias MYQ2="RQ_Q=/path/to/myq2 rq"
200
+
201
+ would allow syntax like
202
+
203
+ MYQ2 submit < joblist
204
+
205
+ MODES
206
+
207
+ rq operates in modes create, submit, resubmit, list, status, delete, update,
208
+ query, execute, configure, snapshot, lock, backup, rotate, feed, recover,
209
+ ioview, cron, help, and a few others. the meaning of 'mode_args' will
210
+ naturally change depending on the mode of operation.
211
+
212
+ the following mode abbreviations exist, note that not all modes have
213
+ abbreviations
214
+
215
+ c => create
216
+ s => submit
217
+ r => resubmit
218
+ l => list
219
+ ls => list
220
+ t => status
221
+ d => delete
222
+ rm => delete
223
+ u => update
224
+ q => query
225
+ e => execute
226
+ C => configure
227
+ S => snapshot
228
+ L => lock
229
+ b => backup
230
+ R => rotate
231
+ f => feed
232
+ io => ioview
233
+ 0 => stdin
234
+ 1 => stdout
235
+ 2 => stderr
236
+ h => help
237
+
238
+
239
+ create, c :
240
+
241
+ creates a queue. the queue must be located on an nfs mounted file system
242
+ visible from all nodes intended to run jobs from it. nfs locking must be
243
+ functional on this file system.
244
+
245
+ examples :
246
+
247
+ 0) to create a queue
248
+ ~ > rq /path/to/nfs/mounted/q create
249
+
250
+ or, using the abbreviation
251
+
252
+ ~ > rq /path/to/nfs/mounted/q c
253
+
254
+
255
+ submit, s :
256
+
257
+ submit jobs to a queue to be proccesed by some feeding node. any
258
+ 'mode_args' are taken as the command to run. note that 'mode_args' are
259
+ subject to shell expansion - if you don't understand what this means do
260
+ not use this feature and pass jobs on stdin.
261
+
262
+ when running in submit mode a file may by specified as a list of commands
263
+ to run using the '--infile, -i' option. this file is taken to be a
264
+ newline separated list of commands to submit, blank lines and comments (#)
265
+ are allowed. if submitting a large number of jobs the input file method
266
+ is MUCH, more efficient. if no commands are specified on the command line
267
+ rq automatically reads them from stdin. yaml formatted files are also
268
+ allowed as input (http://www.yaml.org/) - note that the output of nearly
269
+ all rq commands is valid yaml and may, therefore, be piped as input into
270
+ the submit command. the leading '---' of yaml file may not be omitted.
271
+
272
+ when submitting the '--priority, -p' option can be used here to determine
273
+ the priority of jobs. priorities may be any whole number including
274
+ negative ones - zero is the default. note that submission of a high
275
+ priority job will NOT supplant a currently running low priority job, but
276
+ higher priority jobs WILL always migrate above lower priority jobs in the
277
+ queue in order that they be run as soon as possible. constant submission
278
+ of high priority jobs may create a starvation situation whereby low
279
+ priority jobs are never allowed to run. avoiding this situation is the
280
+ responsibility of the user. the only guaruntee rq makes regarding job
281
+ execution is that jobs are executed in an 'oldest-highest-priority' order
282
+ and that running jobs are never supplanted. jobs submitted with the
283
+ '--stage' option will not be eligible to be run by any node and will
284
+ remain in a 'holding' state until updated (see update mode) into the
285
+ 'pending' mode, this option allows jobs to entered, or 'staged', in the
286
+ queue and then made candidates for running at a later date.
287
+
288
+ rq allows the stdin of commands to be provided and also captures the
289
+ stdout and stderr of any job run (of course standard shell redirects may
290
+ be used as well) and all three will be stored in a directory relative the
291
+ the queue itself. the stdin/stdout/stderr files are stored by job id and
292
+ there location (though relative to the queue) is shown in the output of
293
+ 'list' (see docs for list).
294
+
295
+
296
+ examples :
297
+
298
+ 0) submit the job ls to run on some feeding host
299
+
300
+ ~ > rq q s ls
301
+
302
+ 1) submit the job ls to run on some feeding host, at priority 9
303
+
304
+ ~ > rq -p9 q s ls
305
+
306
+ 2) submit a list of jobs from file. note the '-' used to specify
307
+ reading jobs from stdin
308
+
309
+ ~ > cat joblist
310
+ job1.sh
311
+ job2.sh
312
+ job2.sh
313
+
314
+ ~ > rq q submit --infile=joblist
315
+
316
+ 3) submit a joblist on stdin
317
+
318
+ ~ > cat joblist | rq q submit -
319
+
320
+ or
321
+
322
+ ~ > rq q submit - <joblist
323
+
324
+ 4) submit cat as a job, providing the stdin for cat from the file cat.in
325
+
326
+ ~ > rq q submit cat --stdin=cat.in
327
+
328
+ 5) submit cat as a job, providing the stdin for the cat job on stdin
329
+
330
+ ~ > cat cat.in | rq q submit cat --stdin=-
331
+
332
+ or
333
+
334
+ ~ > rq q submit cat --stdin=- <cat.in
335
+
336
+ 6) submit 42 priority 9 jobs from a command file, marking them as
337
+ 'important' using the '--tag, -t' option.
338
+
339
+ ~ > wc -l cmdfile
340
+ 42
341
+
342
+ ~ > rq -p9 -timportant q s < cmdfile
343
+
344
+ 6) re-submit all the 'important' jobs (see 'query' section below)
345
+
346
+ ~ > rq q query tag=important | rq q s -
347
+
348
+ 8) re-submit all jobs which are already finished (see 'list' section
349
+ below)
350
+
351
+ ~ > rq q l f | rq q s
352
+
353
+
354
+ 9) stage the job wont_run_yet to the queue in a 'holding' state. no
355
+ feeder will run this job until it's state is upgraded to 'pending'
356
+
357
+ ~ > rq q s --stage wont_run_yet
358
+
359
+
360
+ resubmit, r :
361
+
362
+ resubmit jobs back to a queue to be proccesed by a feeding node. resubmit
363
+ is essentially equivalent to submitting a job that is already in the queue
364
+ as a new job and then deleting the original job except that using resubmit
365
+ is atomic and, therefore, safer and more efficient. resubmission respects
366
+ any previous stdin provided for job input. read docs for delete and
367
+ submit for more info.
368
+
369
+ examples :
370
+
371
+ 0) resubmit job 42 to the queue
372
+
373
+ ~> rq q resubmit 42
374
+
375
+ 1) resubmit all failed jobs
376
+
377
+ ~> rq q query exit_status!=0 | rq q resubmit -
378
+
379
+ 2) resubmit job 4242 with different stdin
380
+
381
+ ~ rq q resubmit 4242 --stdin=new_stdin.in
382
+
383
+
384
+ list, l, ls :
385
+
386
+ list mode lists jobs of a certain state or job id. state may be one of
387
+ pending, holding, running, finished, dead, or all. any 'mode_args' that
388
+ are numbers are taken to be job id's to list.
389
+
390
+ states may be abbreviated to uniqueness, therefore the following shortcuts
391
+ apply :
392
+
393
+ p => pending
394
+ h => holding
395
+ r => running
396
+ f => finished
397
+ d => dead
398
+ a => all
399
+
400
+ examples :
401
+
402
+ 0) show everything in q
403
+ ~ > rq q list all
404
+
405
+ or
406
+
407
+ ~ > rq q l all
408
+
409
+ or
410
+
411
+ ~ > export RQ_Q=q
412
+ ~ > rq l
413
+
414
+ 1) show q's pending jobs
415
+ ~ > rq q list pending
416
+
417
+ 2) show q's running jobs
418
+ ~ > rq q list running
419
+
420
+ 3) show q's finished jobs
421
+ ~ > rq q list finished
422
+
423
+ 4) show job id 42
424
+ ~ > rq q l 42
425
+
426
+ 5) show q's holding jobs
427
+ ~ > rq q list holding
428
+
429
+
430
+ status, t :
431
+
432
+ status mode shows the global state the queue and statistics on it's the
433
+ cluster's performance. there are no 'mode_args'. the meaning of each
434
+ state is as follows:
435
+
436
+ pending => no feeder has yet taken this job
437
+ holding => a hold has been placed on this job, thus no feeder will start
438
+ it
439
+ running => a feeder has taken this job
440
+ finished => a feeder has finished this job
441
+ dead => rq died while running a job, has restarted, and moved
442
+ this job to the dead state
443
+
444
+ note that rq cannot move jobs into the dead state unless it has been
445
+ restarted. this is because no node has any knowledge of other nodes and
446
+ cannot possibly know if a job was started on a node that subsequently
447
+ died, or that it is simply taking a very long time to complete. only the
448
+ node that dies, upon restart, can determine that it owns jobs that 'were
449
+ started before it started running jobs', an impossibility, and move these
450
+ jobs into the dead state.
451
+
452
+ normally only a machine crash would cause a job to be placed into the dead
453
+ state. dead jobs are automatically restarted if, and only if, the job was
454
+ submitted with the '--restartable' flag.
455
+
456
+ status breaks down a variety of canned statistics about a nodes'
457
+ performance based solely on the jobs currently in the queue. only one
458
+ option affects the ouput: '--exit'. this option is used to specify
459
+ additionaly exit code mappings on which to report. normally rq will
460
+ report any job with an exit code of 0 as being 'successes' and any job
461
+ with an exit code that is not 0, or a status of 'dead', as being
462
+ 'failures'. if the '--exit' switch is used then additional mappings can
463
+ be specified, note that the the semantics for 'successes' and 'failures'
464
+ does not change - this keyword specifies extra mappings.
465
+
466
+ examples :
467
+
468
+ 0) show q's status
469
+
470
+ ~ > rq q t
471
+
472
+ 2) show q's status, consider any exit code of 42 will be listed as 'ok'
473
+
474
+ ~ > rq q t --exit ok=42
475
+
476
+ 3) show q's status, consider any exit code of 42 or 43 will be listed as
477
+ 'ok' and 127 will be listed as 'command_not_found'. notice the quoting
478
+ required.
479
+
480
+ ~ > rq q t --exit 'ok=42,43 command_not_found=127'
481
+
482
+
483
+ delete, d :
484
+
485
+ delete combinations of pending, holding, finished, dead, or jobs specified
486
+ by jid. the delete mode is capable of parsing the output of list and
487
+ query modes, making it possible to create custom filters to delete jobs
488
+ meeting very specific conditions.
489
+
490
+ 'mode_args' are the same as for list.
491
+
492
+ note that it is NOT possible to delete a running job. rq has a
493
+ decentralized architechture which means that compute nodes are completely
494
+ independant of one another; an extension is that there is no way to
495
+ communicate the deletion of a running job from the queue the the node
496
+ actually running that job. it is not an error to force a job to die
497
+ prematurely using a facility such as an ssh command spawned on the remote
498
+ host to kill it. once a job has been noted to have finished, whatever the
499
+ exit status, it can be deleted from the queue.
500
+
501
+ examples :
502
+
503
+ 0) delete all pending, finished, and dead jobs from a queue
504
+
505
+ ~ > rq q d all
506
+
507
+ 1) delete all pending jobs from a queue
508
+
509
+ ~ > rq q d p
510
+
511
+ 2) delete all finished jobs from a queue
512
+
513
+ ~ > rq q d f
514
+
515
+ 3) delete jobs via hand crafted filter program
516
+
517
+ ~ > rq q list | yaml_filter_prog | rq q d -
518
+
519
+ an example ruby filter program (you have to love this)
520
+
521
+ ~ > cat yaml_filter_prog
522
+ require 'yaml'
523
+ joblist = YAML::load STDIN
524
+ y joblist.select{|job| job['command'] =~ /bombing_program/}
525
+
526
+ this program reads the list of jobs (yaml) from stdin and then dumps
527
+ only those jobs whose command matches 'bombing_program', which is
528
+ subsequently piped to the delete command.
529
+
530
+
531
+ update, u :
532
+
533
+ update assumes all leading arguments are jids to update with subsequent
534
+ key=value pairs. currently only the 'command', 'priority', and 'tag'
535
+ fields of pending jobs can be generically updated and the 'state' field
536
+ may be toggled between pending and holding.
537
+
538
+ examples:
539
+
540
+ 0) update the priority of job 42
541
+
542
+ ~ > rq q update 42 priority=7
543
+
544
+ 1) update the priority of all pending jobs
545
+
546
+ ~ > rq q update pending priority=7
547
+
548
+ 2) query jobs with a command matching 'foobar' and update their command
549
+ to be 'barfoo'
550
+
551
+ ~ > rq q q "command like '%foobar%'" |\\
552
+ rq q u command=barfoo
553
+
554
+ 3) place a hold on jid 2
555
+
556
+ ~ > rq q u 2 state=holding
557
+
558
+ 4) place a hold on all jobs with tag=disk_filler
559
+
560
+ ~ > rq q q tag=disk_filler | rq q u state=holding -
561
+
562
+ 5) remove the hold on jid 2
563
+
564
+ ~ > rq q u 2 state=pending
565
+
566
+
567
+ query, q :
568
+
569
+ query exposes the database more directly the user, evaluating the where
570
+ clause specified on the command line (or read from stdin). this feature
571
+ can be used to make a fine grained slection of jobs for reporting or as
572
+ input into the delete command. you must have a basic understanding of SQL
573
+ syntax to use this feature, but it is fairly intuitive in this limited
574
+ capacity.
575
+
576
+ examples:
577
+
578
+ 0) show all jobs submitted within a specific 10 minute range
579
+
580
+ ~ > a='2004-06-29 22:51:00'
581
+
582
+ ~ > b='2004-06-29 22:51:10'
583
+
584
+ ~ > rq q query "started >= '$a' and started < '$b'"
585
+
586
+ 1) shell quoting can be tricky here so input on stdin is also allowed to
587
+ avoid shell expansion
588
+
589
+ ~ > cat constraints.txt
590
+ started >= '2004-06-29 22:51:00' and
591
+ started < '2004-06-29 22:51:10'
592
+
593
+ ~ > rq q query < contraints.txt
594
+ or (same thing)
595
+
596
+ ~ > cat contraints.txt| rq q query -
597
+
598
+ 2) this query output might then be used to delete those jobs
599
+
600
+ ~ > cat contraints.txt | rq q q - | rq q d -
601
+
602
+ 3) show all jobs which are either finished or dead
603
+
604
+ ~ > rq q q "state='finished' or state='dead'"
605
+
606
+ 4) show all jobs which have non-zero exit status
607
+
608
+ ~ > rq q query exit_status!=0
609
+
610
+ 5) if you plan to query groups of jobs with some common feature consider
611
+ using the '--tag, -t' feature of the submit mode which allows a user to
612
+ tag a job with a user defined string which can then be used to easily
613
+ query that job group
614
+
615
+ ~ > rq q submit --tag=my_jobs - < joblist
616
+
617
+ ~ > rq q query tag=my_jobs
618
+
619
+
620
+ 6) in general all but numbers will need to be surrounded by single
621
+ quotes unless the query is a 'simple' one. a simple query is a query
622
+ with no boolean operators, not quotes, and where every part of it looks
623
+ like
624
+
625
+ key op value
626
+
627
+ with ** NO SPACES ** between key, op, and value. if, and only if,
628
+ the query is 'simple' rq will contruct the where clause
629
+ appropriately. the operators accepted, and their meanings, are
630
+
631
+ = : equivalence : sql =
632
+ =~ : matches : sql like
633
+ !~ : not matches : sql not like
634
+
635
+ match, in the context is ** NOT ** a regular expression but a sql
636
+ style string match. about all you need to know about sql matches is
637
+ that the '%' char matches anything. multiple simple queries will be
638
+ joined with boolean 'and'
639
+
640
+ this sounds confusing - it isn't. here are some examples of simple
641
+ queries
642
+
643
+ 6.a)
644
+ query :
645
+ rq q query tag=important
646
+
647
+ where_clause :
648
+ "( tag = 'important' )"
649
+
650
+ 6.b)
651
+ query :
652
+ rq q q priority=6 restartable=true
653
+
654
+ where_clause :
655
+ "( priority = 6 ) and ( restartable = 'true' )"
656
+
657
+ 6.c)
658
+ query :
659
+ rq q q command=~%bombing_job% runner=~%node_1%
660
+
661
+ where_clause :
662
+ "( command like '%bombing_job%') and (runner like '%node_1%')"
663
+
664
+
665
+ execute, e :
666
+
667
+ execute mode is to be used by expert users with a knowledge of sql syntax
668
+ only. it follows the locking protocol used by rq and then allows the user
669
+ to execute arbitrary sql on the queue. unlike query mode a write lock on
670
+ the queue is obtained allowing a user to definitively shoot themselves in
671
+ the foot. for details on a queue's schema the file 'db.schema' in the
672
+ queue directory should be examined.
673
+
674
+ examples :
675
+
676
+ 0) list all jobs
677
+
678
+ ~ > rq q execute 'select * from jobs'
679
+
680
+
681
+ configure, C :
682
+
683
+ this mode is not supported yet.
684
+
685
+
686
+ snapshot, p :
687
+
688
+ snapshot provides a means of taking a snapshot of the q. use this feature
689
+ when many queries are going to be run; for example when attempting to
690
+ figure out a complex pipeline command your test queries will not compete
691
+ with the feeders for the queue's lock. you should use this option
692
+ whenever possible to avoid lock competition.
693
+
694
+ examples:
695
+
696
+ 0) take a snapshot using default snapshot naming, which is made via the
697
+ basename of the q plus '.snapshot'
698
+
699
+ ~ > rq /path/to/nfs/q snapshot
700
+
701
+ 1) use this snapshot to chceck status
702
+
703
+ ~ > rq ./q.snapshot status
704
+
705
+ 2) use the snapshot to see what's running on which host
706
+
707
+ ~ > rq ./q.snapshot list running | grep `hostname`
708
+
709
+ note that there is also a snapshot option - this option is not the same as
710
+ the snapshot command. the option can be applied to ANY command. if in
711
+ effect then that command will be run on a snapshot of the database and the
712
+ snapshot then immediately deleted. this is really only useful if one were
713
+ to need to run a command against a very heavily loaded queue and did not
714
+ wish to wait to obtain the lock. eg.
715
+
716
+ 0) get the status of a heavily loaded queue
717
+
718
+ ~ > rq q t --snapshot
719
+
720
+ 1) same as above
721
+
722
+ ~ > rq q t -s
723
+
724
+ ** IMPORTANT **
725
+
726
+ a really great way to hang all processing in your queue is to do this
727
+
728
+ rq q list | less
729
+
730
+ and then leave for the night. you hold a read lock you won't release
731
+ until less dies. this is what snapshot is made for! use it like
732
+
733
+ rq q list -s | less
734
+
735
+ now you've taken a snapshot of the queue to list so your locks affect no
736
+ one.
737
+
738
+
739
+ lock, L :
740
+
741
+ lock the queue and then execute an arbitrary shell command. lock mode
742
+ uses the queue's locking protocol to safely obtain a lock of the specified
743
+ type and execute a command on the user's behalf. lock type must be one of
744
+
745
+ (r)ead | (sh)ared | (w)rite | (ex)clusive
746
+
747
+ examples :
748
+
749
+ 0) get a read lock on the queue and make a backup
750
+
751
+ ~ > rq q L read -- cp -r q q.bak
752
+
753
+ (the '--' is needed to tell rq to stop parsing command line
754
+ options which allows the '-r' to be passed to the 'cp' command)
755
+
756
+ ** IMPORTANT **
757
+
758
+ this is another fantastic way to freeze your queue - use with care!
759
+
760
+
761
+ backup, b :
762
+
763
+ backup mode is exactly the same as getting a read lock on the queue and
764
+ making a copy of it. this mode is provided as a convenience.
765
+
766
+ 0) make a backup of the queue using default naming ( qname + timestamp + .bak )
767
+
768
+ ~ > rq q b
769
+
770
+ 1) make a backup of the queue as 'q.bak'
771
+
772
+ ~ > rq q b q.bak
773
+
774
+
775
+ rotate, r :
776
+
777
+ rotate mode is conceptually similar to log rolling. normally the list of
778
+ finished jobs will grow without bound in a queue unless they are manually
779
+ deleted. rotation is a method of trimming finished jobs from a queue
780
+ without deleting them. the method used is that the queue is copied to a
781
+ 'rotation'; all jobs that are dead or finished are deleted from the
782
+ original queue and all pending and running jobs are deleted from the
783
+ rotation. in this way the rotation becomes a record of the queue's
784
+ finished and dead jobs at the time the rotation was made.
785
+
786
+ 0) rotate a queue using default rotation name
787
+
788
+ ~ > rq q rotate
789
+
790
+ 1) rotate a queue naming the rotation
791
+
792
+ ~ > rq q rotate q.rotation
793
+
794
+ 2) a crontab entry like this could be used to rotate a queue daily
795
+
796
+ 59 23 * * * rq q rotate `date +q.%Y%m%d`
797
+
798
+
799
+ feed, f :
800
+
801
+ take jobs from the queue and run them on behalf of the submitter as
802
+ quickly as possible. jobs are taken from the queue in an 'oldest highest
803
+ priority' first order.
804
+
805
+ feeders can be run from any number of nodes allowing you to harness the
806
+ CPU power of many nodes simoultaneously in order to more effectively
807
+ clobber your network, anoy your sysads, and set output raids on fire.
808
+
809
+ the most useful method of feeding from a queue is to do so in daemon mode
810
+ so that if the process loses it's controling terminal it will not exit
811
+ when you exit your terminal session. use the '--daemon, -d' option to
812
+ accomplish this. by default only one feeding process per host per queue
813
+ is allowed to run at any given moment. because of this it is acceptable
814
+ to start a feeder at some regular interval from a cron entry since, if a
815
+ feeder is alreay running, the process will simply exit and otherwise a new
816
+ feeder will be started. in this way you may keep feeder processing
817
+ running even acroess machine reboots without requiring sysad intervention
818
+ to add an entry to the machine's startup tasks.
819
+
820
+
821
+ examples :
822
+
823
+ 0) feed from a queue verbosely for debugging purposes, using a minimum
824
+ and maximum polling time of 2 and 4 respectively. you would NEVER
825
+ specify polling times this brief except for debugging purposes!!!
826
+
827
+ ~ > rq q feed -v4 --min_sleep=2 --max_sleep=4
828
+
829
+ 1) same as above, but viewing the executed sql as it is sent to the
830
+ database
831
+
832
+ ~ > RQ_SQL_DEBUG=1 rq q feed -v4 --min_sleep=2 --max_sleep=4
833
+
834
+ 2) feed from a queue in daemon mode - logging to /home/ahoward/rq.log
835
+
836
+ ~ > rq q feed --daemon -l/home/$USER/rq.log
837
+
838
+ log rolling in daemon mode is automatic so your logs should never
839
+ need to be deleted to prevent disk overflow.
840
+
841
+
842
+ start :
843
+
844
+ the start mode is equivalent to running the feed mode except the --daemon
845
+ is implied so the process instantly goes into the background. also, if no
846
+ log (--log) is specified in start mode a default one is used. the default
847
+ is /home/$USER/$BASENAME_OF_Q.log
848
+
849
+ examples :
850
+
851
+ 0) start a daemon process feeding from q
852
+
853
+ ~ > rq q start
854
+
855
+ 1) use something like this sample crontab entry to keep a feeder running
856
+ forever - it attempts to (re)start every fifteen minutes but exits if
857
+ another process is already feeding. output is only created when the
858
+ daemon is started so your mailbox will not fill up with this crontab
859
+ entry:
860
+
861
+ #
862
+ # crontab.sample
863
+ #
864
+
865
+ */15 * * * * /path/to/bin/rq /path/to/q start
866
+
867
+ and entry like this on every node in your cluster is all that's needed
868
+ to keep your cluster going - even after a reboot.
869
+
870
+
871
+ shutdown :
872
+
873
+ tell a running feeder to finish any pending jobs and then to exit. this
874
+ is equivalent to sending signal 'SIGTERM' to the process - this is what
875
+ using 'kill pid' does by default.
876
+
877
+ examples :
878
+
879
+ 0) stop a feeding process, if any, that is feeding from q. allow all
880
+ jobs to be finished first.
881
+
882
+ ~ > rq q shutdown
883
+
884
+ ** VERY IMPORTANT **
885
+
886
+ if you are keeping your feeder alive with a crontab entry you'll need to
887
+ comment it out before doing this or else it will simply re-start!!!
888
+
889
+ stop :
890
+
891
+ tell any running feeder to stop NOW. this sends signal 'SIGKILL' (-9) to
892
+ the feeder process. the same warning as for shutdown applies!!!
893
+
894
+ examples :
895
+
896
+ 0) stop a feeding process, if any, that is feeding from q. allow NO
897
+ jobs to be finished first - exit instantly.
898
+
899
+ ~ > rq q stop
900
+
901
+ cron :
902
+
903
+ when given 'start' for 'mode_args' this option automatically adds a
904
+ crontab entry to keep a feeder alive indefinitely and starts a feeder in
905
+ the background. this is a shortcut to start a feeder and ensure it stays
906
+ running forever, even across re-boots.
907
+
908
+ 'stop' as an argument applys the inverse option: any crontab entry is
909
+ removed and the daemon shutdown nicely. a second argument of 'hard' will
910
+ do a stop instead of a shutdown.
911
+
912
+ the addition and subtraction of crontab entries is robust, however, if you
913
+ already have crontab lines maintaining your feeders with a vastly
914
+ different syntax it would be best to shut down, remove them, and then let
915
+ rq manage them. then again, some people are quite brave...
916
+
917
+ examples :
918
+
919
+ 0) automatically add crontab entry and start daemon feeder
920
+
921
+ ~ > rq q cron start
922
+
923
+ 1) automatically remove crontab entry and shutdown daemon feeder nicely
924
+
925
+ ~ > rq q cron shutdown
926
+
927
+ 2) the same, but using stop instead of shutdown
928
+
929
+ ~ > rq q cron stop
930
+
931
+ pid :
932
+
933
+ show the pid, if any, of the feeder on this host
934
+
935
+ ~ > rq q feeder
936
+ ---
937
+ pid : 3176
938
+
939
+
940
+ ioview, io :
941
+
942
+ as shown in the description for submit, a job maybe be provided stdin
943
+ during job submission. the stdout and stderr of the job are also captured
944
+ as the job is run. all three streams are captured in files located
945
+ relative to the queue. so, if one has submitted a job, and it's jid was
946
+ shown to be 42, by using something like
947
+
948
+ ~ > rq /path/to/q submit myjob --stdin=myjob.in
949
+ ---
950
+ -
951
+ jid : 42
952
+ priority : 0
953
+ ...
954
+ stdin : stdin/42
955
+ stdout : stdout/42
956
+ stderr : stderr/42
957
+ ...
958
+ command : myjob
959
+
960
+ the stdin file will exists as soon as the job is submitted and the others
961
+ will exist once the job has begun running. note that these paths are
962
+ shown relative to the queue. in this case the actual paths would be
963
+
964
+ /path/to/q/stdin/42
965
+ /path/to/q/stdout/42
966
+ /path/to/q/stderr/42
967
+
968
+ but, since our queue is nfs mounted the /path/to/q may or may not be the
969
+ same on every host. thus the path is a relative one. this can make it
970
+ anoying to view these files, but rq assists here with the ioview command.
971
+ the ioview command spawns an external editor to view all three files.
972
+ it's use is quite simple
973
+
974
+ examples :
975
+
976
+ 0) view the stdin/stdout/stderr of job id 42
977
+
978
+ ~ > rq q ioview 42
979
+
980
+ by default this will open up all three files in vim. the editor command
981
+ can be specified using the '--editor' option or the ENV var RQ_EDITOR.
982
+ the default value is 'vim -R -o' which allows all three files to be opened
983
+ in a single window.
984
+
985
+
986
+ stdin, 0 :
987
+
988
+ dump the stdinput (if any) provided to the job
989
+
990
+ examples :
991
+
992
+ 0) dump the stdin for jid 42
993
+
994
+ ~ > rq q stdin 42
995
+
996
+
997
+ stdout, 1 :
998
+
999
+ dump the stdoutput (if any) created by the job
1000
+
1001
+ examples :
1002
+
1003
+ 0) dump the stdout for jid 42
1004
+
1005
+ ~ > rq q stdout 42
1006
+
1007
+
1008
+ stderr, 2 :
1009
+
1010
+ dump the stderrput (if any) created by the job
1011
+
1012
+ examples :
1013
+
1014
+ 0) dump the stderr for jid 42
1015
+
1016
+ ~ > rq q stderr 42
1017
+
1018
+
1019
+ stdin4 :
1020
+
1021
+ show the path used for the stdin of a jid
1022
+
1023
+ examples :
1024
+
1025
+ 0) show which file has job 42's stdin
1026
+
1027
+ ~ > rq q stdin4 42
1028
+
1029
+
1030
+ stdout4 :
1031
+
1032
+ show the path used for the stdout of a jid
1033
+
1034
+ examples :
1035
+
1036
+ 0) show which file has job 42's stdout
1037
+
1038
+ ~ > rq q stdout4 42
1039
+
1040
+
1041
+ stderr4 :
1042
+
1043
+ show the path used for the stderr of a jid
1044
+
1045
+ examples :
1046
+
1047
+ 0) show which file has job 42's stderr
1048
+
1049
+ ~ > rq q stderr4 42
1050
+
1051
+
1052
+ recover :
1053
+
1054
+ it is possible that a hardware failure might corrupt an rq database. this
1055
+ isn't the kind of thing people like hearing, but it's true - hardware has
1056
+ errors. in these situations a database can sometimes be readable, but not
1057
+ writable, or some other combination. this has been reported only a
1058
+ handful of times, nevertheless, this command wraps sqlite recovery to get
1059
+ you rolling again, it's acceptable to perform recovery on a live rq
1060
+ database with active feeders
1061
+
1062
+ examples :
1063
+
1064
+ 0) recover!
1065
+
1066
+ ~ > rq q recover
1067
+
1068
+
1069
+ help, h :
1070
+
1071
+ this message
1072
+
1073
+ examples :
1074
+
1075
+ 0) get this message
1076
+
1077
+ ~> rq q help
1078
+
1079
+ or
1080
+
1081
+ ~> rq help
1082
+
1083
+ NOTES
1084
+
1085
+ - realize that your job is going to be running on a remote host and this has
1086
+ implications. paths, for example, should be absolute, not relative.
1087
+ specifically the submitted job script must be visible from all hosts
1088
+ currently feeding from a queue as must be the input and output
1089
+ files/directories.
1090
+
1091
+ - jobs are currently run under the bash shell using the --login option.
1092
+ therefore any settings in your .bashrc will apply - specifically your PATH
1093
+ setting. you should not, however, rely on jobs running with any given
1094
+ environment.
1095
+
1096
+ - you need to consider __CAREFULLY__ what the ramifications of having
1097
+ multiple instances of your program all potentially running at the same
1098
+ time will be. for instance, it is beyond the scope of rq to ensure
1099
+ multiple instances of a given program will not overwrite each others
1100
+ output files. coordination of programs is left entirely to the user.
1101
+
1102
+ - the list of finished jobs will grow without bound unless you sometimes
1103
+ delete some (all) of them. the reason for this is that rq cannot know
1104
+ when the user has collected the exit_status of a given job, and so keeps
1105
+ this information in the queue forever until instructed to delete it. if
1106
+ you have collected the exit_status of you job(s) it is not an error to
1107
+ then delete that job from the finished list - the information is kept for
1108
+ your informational purposes only. in a production system it would be
1109
+ normal to periodically save, and then delete, all finished jobs.
1110
+
1111
+ - know that it is a VERY bad idea to spawn several dozen process all
1112
+ reading/writing huge output files to a single NFS server. use this
1113
+ paradigm instead
1114
+
1115
+ * copy/move data from global input space to local disk
1116
+ * process data
1117
+ * move data on local disk to global output space
1118
+
1119
+ this, of course, applies to any nfs processing, not just those jobs
1120
+ submitted to rq
1121
+
1122
+ the vsftp daemon is an excellent utility to have running on hosts in your
1123
+ cluster so anonymous ftp can be used to get/put data between any two
1124
+ hosts.
1125
+
1126
+ - know that nfs locking is very, very easy to break with firewalls put in
1127
+ place by overzealous system administrators. be postive not only that nfs
1128
+ locking works, but that lock recovery server/client crash or reboot works
1129
+ as well. http://nfs.sourceforge.net/ is the place to learn about NFS. my
1130
+ experience thus far is that there are ZERO properly configured NFS
1131
+ installations in the world. please test yours. contact me for a simple
1132
+ script which can assist you. beer donations required as payment.
1133
+
1134
+ ENVIRONMENT
1135
+
1136
+ RQ_Q: set to the full path of nfs mounted queue
1137
+
1138
+ the queue argument to all commands may be omitted if, and only if, the
1139
+ environment variable 'RQ_Q' contains the full path to the q. eg.
1140
+
1141
+ ~ > export RQ_Q=/full/path/to/my/q
1142
+
1143
+ this feature can save a considerable amount of typing for those weak of
1144
+ wrist.
1145
+
1146
+ a shell script like this can also be used to avoid needing to type the
1147
+ queue name each and every time
1148
+
1149
+ ~ > cat my_q
1150
+ #!/bin/sh
1151
+ rq /full/path/to/my/q "$@"
1152
+
1153
+ and then all operations become, for example
1154
+
1155
+ ~> my_q submit my_mob
1156
+ ~> my_q status
1157
+ ~> my_q delete 42
1158
+
1159
+ RQ_OPTS | RQ_OPTIONS: specify extra options
1160
+
1161
+ this ENV var can be used to specify options which should always apply, for
1162
+ example
1163
+
1164
+ ~ > export RQ_OPTS=--restartable
1165
+
1166
+ and shell script like this might be used to mark jobs submitted by a
1167
+ certain user and to always submit them at a negative priority
1168
+
1169
+ ~ > cat username_q
1170
+ #!/bin/sh
1171
+ export RQ_OPTS="--tag=username --priority=-42"
1172
+ rq /full/path/to/my/q "$@"
1173
+
1174
+ actual command line options wil always override options given this way
1175
+
1176
+ DIAGNOSTICS
1177
+
1178
+ success : $? == 0
1179
+ failure : $? != 0
1180
+
1181
+ CREDITS
1182
+
1183
+ - kim baugh : patient tester and design input
1184
+ - jeff safran : the guy can break anything
1185
+ - chris elvidge : boss who made it possible
1186
+ - trond myklebust : tons of help with nfs
1187
+ - jamis buck : for writing the sqlite bindings for ruby
1188
+ - _why : for writing yaml for ruby
1189
+ - matz : for writing ruby
1190
+
1191
+ INSTALL
1192
+
1193
+ gem install rq-ruby1.8 (see top of page)
1194
+
1195
+ TEST
1196
+
1197
+ Install rq and
1198
+
1199
+ test_rq.rb
1200
+
1201
+ AUTHOR
1202
+
1203
+ #{ AUTHOR } and #{ AUTHOR2 }
1204
+
1205
+ BUGS
1206
+
1207
+ 0 < bugno && bugno <= 42
1208
+
1209
+ reports on github, or to #{ AUTHOR2 } and #{ AUTHOR }
1210
+
1211
+ SEE ALSO
1212
+
1213
+ #{ WEBSITE } - main website
1214
+
1215
+ usage
1216
+ #--}}}
1217
+ #--}}}
1218
+ end # module Usage
1219
+ #--}}}
1220
+ end # module RQ
1221
+ $__rq_usage__ = __FILE__
1222
+ end