rq 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
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