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/TODO ADDED
@@ -0,0 +1,13 @@
1
+ ---
2
+ - re-think db schema: separate critical info/index for speed?
3
+ - user docs
4
+ - examples
5
+ - installer script
6
+ - api docs
7
+ - rq relay mode (submit and track exit_status in local db)
8
+ - housekeeping - make backups of queue every so often, integrity_checks at
9
+ - scheduled intervals
10
+ - full boolean resource monitoring and resource requests
11
+ - in db message queue to send commands to remote nodes - ttl issues here...
12
+ - track feeders in queue rather than using lock on local file?
13
+ - use nodes to periodically generate stats (cache)
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.7
data/bin/rq ADDED
@@ -0,0 +1,391 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # rq - http://raa.ruby-lang.org/project/rq
4
+ #
5
+ require 'rq'
6
+ #
7
+ # main program class
8
+ #
9
+ class Main
10
+ #{{{
11
+ include RQ
12
+ include RQ::Util
13
+ include RQ::Logging
14
+ include RQ::Usage
15
+
16
+ OPTSPEC =
17
+ #{{{
18
+ [
19
+ [
20
+ '--priority=priority', '-p',
21
+ 'modes <submit> : set the job(s) priority - lowest(0) .. highest(n) - (default 0)'
22
+ ],
23
+ [
24
+ '--tag=tag', '-t',
25
+ 'modes <submit> : set the job(s) user data tag'
26
+ ],
27
+ [
28
+ '--infile=infile', '-i',
29
+ 'modes <submit> : infile'
30
+ ],
31
+ [
32
+ '--quiet', '-q',
33
+ 'modes <submit, feed> : do not echo submitted jobs, fail silently if
34
+ another process is already feeding'
35
+ ],
36
+ [
37
+ '--daemon', '-d',
38
+ 'modes <feed> : spawn a daemon'
39
+ ],
40
+ [
41
+ '--max_feed=max_feed', '-f',
42
+ 'modes <feed> : the maximum number of concurrent jobs run'
43
+ ],
44
+ # [
45
+ # '--name=name',
46
+ # 'set the feeder name - (default q path)'
47
+ # ],
48
+ [
49
+ '--retries=retries', '-r',
50
+ 'modes <feed> : specify transaction retries'
51
+ ],
52
+ [
53
+ '--min_sleep=min_sleep', '-m',
54
+ 'modes <feed> : specify min sleep'
55
+ ],
56
+ [
57
+ '--max_sleep=max_sleep', '-M',
58
+ 'modes <feed> : specify max sleep'
59
+ ],
60
+ [
61
+ '--snapshot', '-s',
62
+ 'operate on snapshot of queue'
63
+ ],
64
+ [
65
+ '--verbosity=verbostiy', '-v',
66
+ '0|fatal < 1|error < 2|warn < 3|info < 4|debug - (default info)'
67
+ ],
68
+ [
69
+ '--log=path','-l',
70
+ 'set log file - (default stderr)'
71
+ ],
72
+ [
73
+ '--log_age=log_age',
74
+ 'daily | weekly | monthly - what age will cause log rolling (default nil)'
75
+ ],
76
+ [
77
+ '--log_size=log_size',
78
+ 'size in bytes - what size will cause log rolling (default nil)'
79
+ ],
80
+ # [
81
+ # '--config=path',
82
+ # 'valid path - specify config file (default nil)'
83
+ # ],
84
+ # [
85
+ # '--template=[path]',
86
+ # 'valid path - generate a template config file in path (default stdout)'
87
+ # ],
88
+ [
89
+ '--help', '-h',
90
+ 'this message'
91
+ ],
92
+ ]
93
+ #}}}
94
+
95
+ CONFIG_DEFAULT_PATH = 'rq.conf'
96
+
97
+ CONFIG_SEARCH_PATH = %w( . ~ /dmsp/reference/etc /usr/local/etc /usr/etc /etc )
98
+
99
+ attr :logger
100
+ attr :argv
101
+ attr :env
102
+ attr :cmd
103
+ attr :options
104
+ attr :qpath
105
+ attr :mode
106
+ attr :q
107
+ attr :daemon
108
+
109
+ def initialize argv = ARGV, env = ENV
110
+ #{{{
111
+ begin
112
+ @logger = Logger::new STDERR
113
+ @argv = mcp(argv.to_a)
114
+ @env = mcp(env.to_hash)
115
+ @cmd = ([$0] + @argv).join(' ')
116
+
117
+ parse_options
118
+
119
+ if(@options.has_key?('help') or @argv.include?('help'))
120
+ usage('port' => STDOUT, 'long' => true)
121
+ exit EXIT_SUCCESS
122
+ end
123
+
124
+ if(@options.has_key?('template') or (idx = @argv.index('template')))
125
+ gen_template(@options['template'] || @argv[idx + 1])
126
+ exit EXIT_SUCCESS
127
+ end
128
+
129
+ parse_argv
130
+
131
+ status = run
132
+
133
+ case status
134
+ when Integer
135
+ exit status
136
+ else
137
+ exit(status ? EXIT_SUCCESS : EXIT_FAILURE)
138
+ end
139
+ rescue => e
140
+ unless SystemExit === e
141
+ logerr e
142
+ exit EXIT_FAILURE
143
+ else
144
+ exit e.status
145
+ end
146
+ end
147
+ #}}}
148
+ end
149
+ def parse_argv
150
+ #{{{
151
+ @qpath = ENV['RQ_Q'] || @argv.shift
152
+ @mode = @argv.shift
153
+ #}}}
154
+ end
155
+ def run
156
+ #{{{
157
+ @qpath = Util::realpath @qpath
158
+
159
+ if @mode.nil? or @mode.strip.empty?
160
+ usage 'port' => STDERR, 'long' => false
161
+ exit EXIT_FAILURE
162
+ end
163
+
164
+ shortcuts = {
165
+ 'c' => 'create',
166
+ 's' => 'submit',
167
+ 'l' => 'list',
168
+ 'ls' => 'list',
169
+ 't' => 'status',
170
+ 'd' => 'delete',
171
+ 'rm' => 'delete',
172
+ 'u' => 'update',
173
+ 'q' => 'query',
174
+ 'e' => 'execute',
175
+ 'C' => 'configure',
176
+ 'S' => 'snapshot',
177
+ 'L' => 'lock',
178
+ 'b' => 'backup',
179
+ 'h' => 'help',
180
+ 'f' => 'feed',
181
+ }
182
+
183
+ if((longmode = shortcuts[@mode]))
184
+ @mode = longmode
185
+ end
186
+
187
+ begin
188
+ case @mode
189
+ when 'create'
190
+ create
191
+ when 'submit'
192
+ submit
193
+ when 'list'
194
+ list
195
+ when 'status'
196
+ status
197
+ when 'delete'
198
+ delete
199
+ when 'update'
200
+ update
201
+ when 'query'
202
+ query
203
+ when 'execute'
204
+ execute
205
+ when 'configure'
206
+ configure
207
+ when 'snapshot'
208
+ snapshot
209
+ when 'lock'
210
+ lock
211
+ when 'backup'
212
+ backup
213
+ when 'help'
214
+ usage 'port' => STDOUT, 'long' => true
215
+ exit EXIT_SUCCESS
216
+ when 'feed'
217
+ feed
218
+ else
219
+ raise "invalid mode <#{ @mode }>"
220
+ end
221
+ rescue Errno::EPIPE => e
222
+ raise if STDOUT.tty?
223
+ end
224
+ #}}}
225
+ end
226
+ def create
227
+ #{{{
228
+ init_logging
229
+ creator = Creator::new self
230
+ creator.create
231
+ #}}}
232
+ end
233
+ def submit
234
+ #{{{
235
+ init_logging
236
+ submitter = Submitter::new self
237
+ submitter.submit
238
+ #}}}
239
+ end
240
+ def list
241
+ #{{{
242
+ init_logging
243
+ lister = Lister::new self
244
+ lister.list
245
+ #}}}
246
+ end
247
+ def status
248
+ #{{{
249
+ init_logging
250
+ statuslister = StatusLister::new self
251
+ statuslister.statuslist
252
+ #}}}
253
+ end
254
+ def delete
255
+ #{{{
256
+ init_logging
257
+ deleter = Deleter::new self
258
+ deleter.delete
259
+ #}}}
260
+ end
261
+ def update
262
+ #{{{
263
+ init_logging
264
+ updater = Updater::new self
265
+ updater.update
266
+ #}}}
267
+ end
268
+ def query
269
+ #{{{
270
+ init_logging
271
+ querier = Querier::new self
272
+ querier.query
273
+ #}}}
274
+ end
275
+ def execute
276
+ #{{{
277
+ init_logging
278
+ executor = Executor::new self
279
+ executor.execute
280
+ #}}}
281
+ end
282
+ def configure
283
+ #{{{
284
+ init_logging
285
+ configurator = Configurator::new self
286
+ configurator.configure
287
+ #}}}
288
+ end
289
+ def snapshot
290
+ #{{{
291
+ init_logging
292
+ snapshotter = Snapshotter::new self
293
+ snapshotter.snapshot
294
+ #}}}
295
+ end
296
+ def lock
297
+ #{{{
298
+ init_logging
299
+ locker = Locker::new self
300
+ locker.lock
301
+ #}}}
302
+ end
303
+ def backup
304
+ #{{{
305
+ init_logging
306
+ backer = Backer::new self
307
+ backer.backup
308
+ #}}}
309
+ end
310
+ def feed
311
+ #{{{
312
+ feeder = Feeder::new self
313
+ feeder.feed
314
+ #}}}
315
+ end
316
+ def parse_options
317
+ #{{{
318
+ @op = OptionParser.new
319
+ @options = {}
320
+ OPTSPEC.each do |spec|
321
+ k = spec.first.gsub(%r/(?:--)|(?:=.*$)|(?:\s+)/o,'')
322
+ @op.def_option(*spec){|v| @options[k] = v}
323
+ end
324
+ @op.parse! @argv
325
+ @options
326
+ #}}}
327
+ end
328
+ def init_logging
329
+ #{{{
330
+ log, log_age, log_size, verbosity =
331
+ @options.values_at 'log', 'log_age', 'log_size', 'verbosity'
332
+ log_age = atoi log_age rescue nil
333
+ log_size = atoi log_size rescue nil
334
+ $logger = @logger = Logger::new(log || STDERR, log_age, log_size)
335
+ #
336
+ # hack to fix Logger sync bug
337
+ #
338
+ class << @logger; attr :logdev unless @logger.respond_to?(:logdev); end
339
+ @logdev = @logger.logdev.dev
340
+ @logdev.sync = true
341
+ level = nil
342
+ verbosity ||= 'info'
343
+ verbosity =
344
+ case verbosity
345
+ when /^\s*(?:4|d|debug)\s*$/io
346
+ level = 'Logging::DEBUG'
347
+ 4
348
+ when /^\s*(?:3|i|info)\s*$/io
349
+ level = 'Logging::INFO'
350
+ 3
351
+ when /^\s*(?:2|w|warn)\s*$/io
352
+ level = 'Logging::WARN'
353
+ 2
354
+ when /^\s*(?:1|e|error)\s*$/io
355
+ level = 'Logging::ERROR'
356
+ 1
357
+ when /^\s*(?:0|f|fatal)\s*$/io
358
+ level = 'Logging::FATAL'
359
+ 0
360
+ else
361
+ abort "illegal verbosity setting <#{ verbosity }>"
362
+ end
363
+ @logger.level = 2 - ((verbosity % 5) - 2)
364
+ debug {"logging level <#{ level }>"}
365
+ @logger
366
+ #}}}
367
+ end
368
+ def init_config
369
+ #{{{
370
+ @config =
371
+ if @options['config']
372
+ ConfigFile::new(@options['config'])
373
+ else
374
+ ConfigFile::any CONFIG_DEFAULT_PATH, CONFIG_SEARCH_PATH
375
+ end
376
+ debug { "config.path <#{ @config.path }>" }
377
+ @config
378
+ #}}}
379
+ end
380
+ def gen_template template
381
+ #{{{
382
+ ConfigFile::gen_template(template)
383
+ self
384
+ #}}}
385
+ end
386
+ #}}}
387
+ end
388
+ #
389
+ # run main program unless included as lib
390
+ #
391
+ Main::new if $0 == __FILE__
@@ -0,0 +1,410 @@
1
+ #!/dmsp/reference/bin/ruby
2
+ #
3
+ # rq - http://raa.ruby-lang.org/project/rq
4
+ #
5
+ require 'rq'
6
+ #
7
+ # main program class
8
+ #
9
+ class Main
10
+ #{{{
11
+ include RQ
12
+ include RQ::Util
13
+ include RQ::Logging
14
+ include RQ::Usage
15
+
16
+ #
17
+ # TODO - pull out config stuff into separate class
18
+ # TODO - add resouce manager
19
+ #
20
+ CONFIG_DEFAULT_PATH = "#{ $0 }.conf"
21
+ CONFIG_SEARCH_PATH = %w(. ~ /usr/local/etc /usr/etc /etc)
22
+
23
+ OPTSPEC =
24
+ #{{{
25
+ [
26
+ [
27
+ '--max_feed', '-f',
28
+ 'the maximum number of concurrent jobs'
29
+ ],
30
+ [
31
+ '--priority', '-p',
32
+ 'set the job priority - lowest(0) .. highest(n) - (default 0)'
33
+ ],
34
+ [
35
+ '--name',
36
+ 'set the feeder name - (default q path)'
37
+ ],
38
+ [
39
+ '--daemon', '-d',
40
+ 'run in daemon mode'
41
+ ],
42
+ [
43
+ '--quiet', '-q',
44
+ 'fail quietly'
45
+ ],
46
+ [
47
+ '--snapshot', '-s',
48
+ 'operate on snapshot of queue'
49
+ ],
50
+ [
51
+ '--retries', '-r',
52
+ 'retries'
53
+ ],
54
+ [
55
+ '--min_sleep', '-m',
56
+ 'min sleep'
57
+ ],
58
+ [
59
+ '--max_sleep', '-M',
60
+ 'max sleep'
61
+ ],
62
+ [
63
+ '--infile', '-i',
64
+ 'infile'
65
+ ],
66
+ [
67
+ '--help', '-h',
68
+ 'this message'
69
+ ],
70
+ [
71
+ '--verbosity=verbostiy', '-v',
72
+ '0|fatal < 1|error < 2|warn < 3|info < 4|debug - (default info)'
73
+ ],
74
+ [
75
+ '--log=path','-l',
76
+ 'set log file - (default stderr)'
77
+ ],
78
+ [
79
+ '--log_age=log_age',
80
+ 'daily | weekly | monthly - what age will cause log rolling (default nil)'
81
+ ],
82
+ [
83
+ '--log_size=log_size',
84
+ 'size in bytes - what size will cause log rolling (default nil)'
85
+ ],
86
+ [
87
+ '--config=path',
88
+ 'valid path - specify config file (default nil)'
89
+ ],
90
+ [
91
+ '--template=[path]',
92
+ 'valid path - generate a template config file in path (default stdout)'
93
+ ],
94
+ ]
95
+ #}}}
96
+
97
+ attr :logger
98
+ attr :argv
99
+ attr :env
100
+ attr :cmd
101
+ attr :options
102
+ attr :qpath
103
+ attr :mode
104
+ attr :q
105
+ attr :daemon
106
+
107
+ def initialize argv = ARGV, env = ENV
108
+ #{{{
109
+ begin
110
+ @logger = Logger::new STDERR
111
+ @argv = mcp(argv.to_a)
112
+ @env = mcp(env.to_hash)
113
+ @cmd = ([$0] + @argv).join(' ')
114
+
115
+ parse_options
116
+
117
+ if @options.has_key? 'help'
118
+ usage('port' => STDOUT, 'long' => true)
119
+ exit EXIT_SUCCESS
120
+ end
121
+
122
+ if @options.has_key? 'template'
123
+ gen_template @options['template']
124
+ exit EXIT_SUCCESS
125
+ end
126
+
127
+ parse_argv
128
+
129
+ status = run
130
+
131
+ case status
132
+ when Integer
133
+ exit status
134
+ else
135
+ exit(status ? EXIT_SUCCESS : EXIT_FAILURE)
136
+ end
137
+ rescue => e
138
+ unless SystemExit === e
139
+ logerr e
140
+ exit EXIT_FAILURE
141
+ else
142
+ exit e.status
143
+ end
144
+ end
145
+ #}}}
146
+ end
147
+ def parse_argv
148
+ #{{{
149
+ @qpath = ENV['RQ_Q'] || @argv.shift
150
+ @mode = @argv.shift
151
+ #}}}
152
+ end
153
+ def run
154
+ #{{{
155
+ if @qpath == 'help'
156
+ usage 'port' => STDOUT, 'long' => true
157
+ exit EXIT_SUCCESS
158
+ end
159
+
160
+ @qpath = Util::realpath @qpath
161
+
162
+ if @mode.nil? or @mode.strip.empty?
163
+ usage 'port' => STDERR, 'long' => false
164
+ exit EXIT_FAILURE
165
+ end
166
+
167
+ shortcuts = {
168
+ 'c' => 'create',
169
+ 's' => 'submit',
170
+ 'l' => 'list',
171
+ 'ls' => 'list',
172
+ 't' => 'status',
173
+ 'd' => 'delete',
174
+ 'rm' => 'delete',
175
+ 'u' => 'update',
176
+ 'q' => 'query',
177
+ 'e' => 'execute',
178
+ 'C' => 'configure',
179
+ 'S' => 'snapshot',
180
+ 'L' => 'lock',
181
+ 'b' => 'backup',
182
+ 'h' => 'help',
183
+ 'f' => 'feed',
184
+ }
185
+
186
+ if((longmode = shortcuts[@mode]))
187
+ @mode = longmode
188
+ end
189
+
190
+ begin
191
+ case @mode
192
+ when 'create'
193
+ create
194
+ when 'submit'
195
+ submit
196
+ when 'list'
197
+ list
198
+ when 'status'
199
+ status
200
+ when 'delete'
201
+ delete
202
+ when 'update'
203
+ update
204
+ when 'query'
205
+ query
206
+ when 'execute'
207
+ execute
208
+ when 'configure'
209
+ configure
210
+ when 'snapshot'
211
+ snapshot
212
+ when 'lock'
213
+ lock
214
+ when 'backup'
215
+ backup
216
+ when 'help'
217
+ usage 'port' => STDOUT, 'long' => true
218
+ exit EXIT_SUCCESS
219
+ when 'feed'
220
+ feed
221
+ else
222
+ raise "invalid mode <#{ @mode }>"
223
+ end
224
+ rescue Errno::EPIPE => e
225
+ raise if STDOUT.tty?
226
+ end
227
+ #}}}
228
+ end
229
+ def create
230
+ #{{{
231
+ init_logging
232
+ creator = Creator::new self
233
+ creator.create
234
+ #}}}
235
+ end
236
+ def submit
237
+ #{{{
238
+ init_logging
239
+ submitter = Submitter::new self
240
+ submitter.submit
241
+ #}}}
242
+ end
243
+ def list
244
+ #{{{
245
+ init_logging
246
+ lister = Lister::new self
247
+ lister.list
248
+ #}}}
249
+ end
250
+ def status
251
+ #{{{
252
+ init_logging
253
+ statuslister = StatusLister::new self
254
+ statuslister.statuslist
255
+ #}}}
256
+ end
257
+ def delete
258
+ #{{{
259
+ init_logging
260
+ deleter = Deleter::new self
261
+ deleter.delete
262
+ #}}}
263
+ end
264
+ def update
265
+ #{{{
266
+ init_logging
267
+ updater = Updater::new self
268
+ updater.update
269
+ #}}}
270
+ end
271
+ def query
272
+ #{{{
273
+ init_logging
274
+ querier = Querier::new self
275
+ querier.query
276
+ #}}}
277
+ end
278
+ def execute
279
+ #{{{
280
+ init_logging
281
+ executor = Executor::new self
282
+ executor.execute
283
+ #}}}
284
+ end
285
+ def configure
286
+ #{{{
287
+ init_logging
288
+ configurator = Configurator::new self
289
+ configurator.configure
290
+ #}}}
291
+ end
292
+ def snapshot
293
+ #{{{
294
+ init_logging
295
+ snapshotter = Snapshotter::new self
296
+ snapshotter.snapshot
297
+ #}}}
298
+ end
299
+ def lock
300
+ #{{{
301
+ init_logging
302
+ locker = Locker::new self
303
+ locker.lock
304
+ #}}}
305
+ end
306
+ def backup
307
+ #{{{
308
+ init_logging
309
+ backer = Backer::new self
310
+ backer.backup
311
+ #}}}
312
+ end
313
+ def feed
314
+ #{{{
315
+ feeder = Feeder::new self
316
+ feeder.feed
317
+ #}}}
318
+ end
319
+ def parse_options
320
+ #{{{
321
+ @op = OptionParser.new
322
+ @options = {}
323
+ OPTSPEC.each do |spec|
324
+ k = spec.first.gsub(%r/(?:--)|(?:=.*$)|(?:\s+)/o,'')
325
+ @op.def_option(*spec){|v| @options[k] = v}
326
+ end
327
+ #begin
328
+ @op.parse! @argv
329
+ #rescue OptionParser::InvalidOption => e
330
+ # preverve unknown options
331
+ #e.recover(argv)
332
+ #end
333
+ @options
334
+ #}}}
335
+ end
336
+ def init_logging
337
+ #{{{
338
+ log, log_age, log_size, verbosity =
339
+ @options.values_at 'log', 'log_age', 'log_size', 'verbosity'
340
+ log_age = atoi log_age rescue nil
341
+ log_size = atoi log_size rescue nil
342
+ $logger = @logger = Logger::new(log || STDERR, log_age, log_size)
343
+ #
344
+ # hack to fix Logger sync bug
345
+ #
346
+ class << @logger; attr :logdev unless @logger.respond_to?(:logdev); end
347
+ @logdev = @logger.logdev.dev
348
+ @logdev.sync = true
349
+ level = nil
350
+ verbosity ||= 'info'
351
+ verbosity =
352
+ case verbosity
353
+ when /^\s*(?:4|d|debug)\s*$/io
354
+ level = 'Logging::DEBUG'
355
+ 4
356
+ when /^\s*(?:3|i|info)\s*$/io
357
+ level = 'Logging::INFO'
358
+ 3
359
+ when /^\s*(?:2|w|warn)\s*$/io
360
+ level = 'Logging::WARN'
361
+ 2
362
+ when /^\s*(?:1|e|error)\s*$/io
363
+ level = 'Logging::ERROR'
364
+ 1
365
+ when /^\s*(?:0|f|fatal)\s*$/io
366
+ level = 'Logging::FATAL'
367
+ 0
368
+ else
369
+ abort "illegal verbosity setting <#{ verbosity }>"
370
+ end
371
+ @logger.level = 2 - ((verbosity % 5) - 2)
372
+ debug {"logging level <#{ level }>"}
373
+ @logger
374
+ #}}}
375
+ end
376
+ def init_config
377
+ #{{{
378
+ @config =
379
+ if @options['config']
380
+ ConfigFile::new(@options['config'])
381
+ else
382
+ ConfigFile::any CONFIG_DEFAULT_PATH, CONFIG_SEARCH_PATH
383
+ end
384
+ debug { "config.path <#{ @config.path }>" }
385
+ debug { "config\n#{ @config.to_hash.to_yaml }\n" }
386
+ @config
387
+ #}}}
388
+ end
389
+ def gen_template template
390
+ #{{{
391
+ ConfigFile::gen_template(template)
392
+ self
393
+ #}}}
394
+ end
395
+ #}}}
396
+ end
397
+ #
398
+ # run main program unless included as lib
399
+ #
400
+ Main::new if $0 == __FILE__
401
+ #
402
+ # the default config is stored here
403
+ #
404
+ __END__
405
+ #
406
+ # default config
407
+ #
408
+
409
+ key0 : value0
410
+ key1 : value1