bj 0.0.1

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/HISTORY ADDED
@@ -0,0 +1,2 @@
1
+ 0.0.1:
2
+ - initial release
data/README ADDED
@@ -0,0 +1,130 @@
1
+ NAME
2
+ bj
3
+
4
+ SYNOPSIS
5
+ bj (migration_code|generate_migration|migrate|setup|run|submit|list|set|config|pid) [options]+
6
+
7
+ DESCRIPTION
8
+ ________________________________
9
+ Overview
10
+ --------------------------------
11
+
12
+ Backgroundjob (Bj) is a simple to use background priority queue for rails.
13
+ Although not yet tested on windows, the design of bj is such that operation
14
+ should be possible on any operating system, including M$.
15
+
16
+ Jobs can be submitted to the queue directly using the api or from the
17
+ commandline using the 'bj' script. For example
18
+
19
+ code:
20
+ Bj.submit 'cat /etc/password'
21
+
22
+ cli:
23
+ bj submit cat /etc/password
24
+
25
+ When used from inside a rails application bj arranges that another process
26
+ will always be running in the background to process the jobs that you submit.
27
+ By using a separate process to run jobs bj does not impact the resource
28
+ utilization of your rails application at all and enables several very cool
29
+ features:
30
+
31
+ 1) Bj allows you to sumbit jobs to any of your configured databases and,
32
+ in each case, spawns a separate background process to run jobs from that
33
+ queue
34
+
35
+ Bj.in :production do
36
+ Bj.submit 'production_job.exe'
37
+ end
38
+
39
+ Bj.in :development do
40
+ Bj.submit 'development_job.exe'
41
+ end
42
+
43
+ 2) Although bj ensures that a process is always running to process
44
+ your jobs, you can start a proces manually. This means that any machine
45
+ capable of seeing your RAILS_ROOT can run jobs for your application, allowing
46
+ one to setup a cluster of machines doing the work of a single front end rails
47
+ applicaiton.
48
+
49
+ ________________________________
50
+ Install
51
+ --------------------------------
52
+
53
+ Bj can be installed two ways: as a gem or as a plugin.
54
+
55
+ gem:
56
+
57
+ 1) $sudo gem install bj
58
+ 2) bj setup ./rails_root/
59
+
60
+ plugin:
61
+
62
+ 1) ./script/plugin install http://codeforpeople.rubyforge.org/svn/rails/plugins/bj
63
+ 2) ./script/bj setup
64
+
65
+ ________________________________
66
+ Api
67
+ --------------------------------
68
+
69
+ submit jobs for background processing. 'jobs' can be a string or array of
70
+ strings. options are applied to each job in the 'jobs', and the list of
71
+ submitted jobs is always returned. options (string or symbol) can be
72
+
73
+ :rails_env => production|development|key_in_database_yml
74
+ when given this keyword causes bj to submit jobs to the
75
+ specified database. default is RAILS_ENV.
76
+
77
+ :priority => any number, including negative ones. default is zero.
78
+
79
+ :tag => a tag added to the job. simply makes searching easier.
80
+
81
+ :env => a hash specifying any additional environment vars the background
82
+ process should have.
83
+
84
+ :stdin => any stdin the background process should have.
85
+
86
+ eg:
87
+
88
+ jobs = Bj.submit 'echo foobar', :tag => 'simple job'
89
+
90
+ jobs = Bj.submit '/bin/cat', :stdin => 'in the hat'
91
+
92
+ jobs = Bj.submit './script/runner ./scripts/a.rb', :rails_env => 'production'
93
+
94
+ when jobs are run, they are run in RAILS_ROOT. various attributes are
95
+ available *only* once the job has finished. you can check whether or not a
96
+ job is finished by using the #finished method, which simple does a reload and
97
+ checks to see if the exit_status is non-nil.
98
+
99
+ eg:
100
+
101
+ jobs = Bj.submit list_of_jobs, :tag => 'important'
102
+ ...
103
+
104
+ jobs.each do |job|
105
+ if job.finished?
106
+ p job.exit_status
107
+ p job.stdout
108
+ p job.stderr
109
+ end
110
+ end
111
+
112
+ See lib/bj/api.rb for more details.
113
+
114
+ PARAMETERS
115
+ --rails_root=rails_root, -R (0 ~> rails_root=)
116
+ the rails_root will be guessed unless you set this
117
+ --rails_env=rails_env, -E (0 ~> rails_env=development)
118
+ set the rails_env
119
+ --log=log, -l (0 ~> log=STDERR)
120
+ set the logfile
121
+ --help, -h
122
+
123
+ AUTHOR
124
+ ara.t.howard@gmail.com
125
+
126
+ URIS
127
+ http://codeforpeople.com/lib/ruby/
128
+ http://rubyforge.org/projects/codeforpeople/
129
+ http://codeforpeople.rubyforge.org/svn/rails/plugins/
130
+
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ * flesh out the cli interface - it's a test only at this point
2
+ * test in windows
3
+ * make sure database.yml is loaded via YAML::load(ERB.new(File.read * "config/database.yml").result)
data/bin/bj ADDED
@@ -0,0 +1,478 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require "bj"
4
+
5
+ Main {
6
+ usage["description"] = <<-txt
7
+ ________________________________
8
+ Overview
9
+ --------------------------------
10
+
11
+ Backgroundjob (Bj) is a simple to use background priority queue for rails.
12
+ Although not yet tested on windows, the design of bj is such that operation
13
+ should be possible on any operating system, including M$.
14
+
15
+ Jobs can be submitted to the queue directly using the api or from the
16
+ commandline using the 'bj' script. For example
17
+
18
+ code:
19
+ Bj.submit 'cat /etc/password'
20
+
21
+ cli:
22
+ bj submit cat /etc/password
23
+
24
+ When used from inside a rails application bj arranges that another process
25
+ will always be running in the background to process the jobs that you submit.
26
+ By using a separate process to run jobs bj does not impact the resource
27
+ utilization of your rails application at all and enables several very cool
28
+ features:
29
+
30
+ 1) Bj allows you to sumbit jobs to any of your configured databases and,
31
+ in each case, spawns a separate background process to run jobs from that
32
+ queue
33
+
34
+ Bj.in :production do
35
+ Bj.submit 'production_job.exe'
36
+ end
37
+
38
+ Bj.in :development do
39
+ Bj.submit 'development_job.exe'
40
+ end
41
+
42
+ 2) Although bj ensures that a process is always running to process
43
+ your jobs, you can start a proces manually. This means that any machine
44
+ capable of seeing your RAILS_ROOT can run jobs for your application, allowing
45
+ one to setup a cluster of machines doing the work of a single front end rails
46
+ applicaiton.
47
+
48
+ ________________________________
49
+ Install
50
+ --------------------------------
51
+
52
+ Bj can be installed two ways: as a gem or as a plugin.
53
+
54
+ gem:
55
+
56
+ 1) $sudo gem install bj
57
+ 2) bj setup ./rails_root/
58
+
59
+ plugin:
60
+
61
+ 1) ./script/plugin install http://codeforpeople.rubyforge.org/svn/rails/plugins/bj
62
+ 2) ./script/bj setup
63
+
64
+ ________________________________
65
+ Api
66
+ --------------------------------
67
+
68
+ submit jobs for background processing. 'jobs' can be a string or array of
69
+ strings. options are applied to each job in the 'jobs', and the list of
70
+ submitted jobs is always returned. options (string or symbol) can be
71
+
72
+ :rails_env => production|development|key_in_database_yml
73
+ when given this keyword causes bj to submit jobs to the
74
+ specified database. default is RAILS_ENV.
75
+
76
+ :priority => any number, including negative ones. default is zero.
77
+
78
+ :tag => a tag added to the job. simply makes searching easier.
79
+
80
+ :env => a hash specifying any additional environment vars the background
81
+ process should have.
82
+
83
+ :stdin => any stdin the background process should have.
84
+
85
+ eg:
86
+
87
+ jobs = Bj.submit 'echo foobar', :tag => 'simple job'
88
+
89
+ jobs = Bj.submit '/bin/cat', :stdin => 'in the hat'
90
+
91
+ jobs = Bj.submit './script/runner ./scripts/a.rb', :rails_env => 'production'
92
+
93
+ when jobs are run, they are run in RAILS_ROOT. various attributes are
94
+ available *only* once the job has finished. you can check whether or not a
95
+ job is finished by using the #finished method, which simple does a reload and
96
+ checks to see if the exit_status is non-nil.
97
+
98
+ eg:
99
+
100
+ jobs = Bj.submit list_of_jobs, :tag => 'important'
101
+ ...
102
+
103
+ jobs.each do |job|
104
+ if job.finished?
105
+ p job.exit_status
106
+ p job.stdout
107
+ p job.stderr
108
+ end
109
+ end
110
+
111
+ See lib/bj/api.rb for more details.
112
+
113
+ ________________________________
114
+ Sponsors
115
+ --------------------------------
116
+ http://www.engineyard.com/
117
+ http://quintess.com/
118
+ http://eparklabs.com/
119
+ txt
120
+
121
+ usage["uris"] = <<-txt
122
+ http://codeforpeople.com/lib/ruby/
123
+ http://rubyforge.org/projects/codeforpeople/
124
+ http://codeforpeople.rubyforge.org/svn/rails/plugins/
125
+ txt
126
+
127
+ author "ara.t.howard@gmail.com"
128
+
129
+ option("rails_root", "R"){
130
+ description "the rails_root will be guessed unless you set this"
131
+ argument_required
132
+ default RAILS_ROOT
133
+ }
134
+
135
+ option("rails_env", "E"){
136
+ description "set the rails_env"
137
+ argument_required
138
+ default RAILS_ENV
139
+ }
140
+
141
+ option("log", "l"){
142
+ description "set the logfile"
143
+ argument_required
144
+ default STDERR
145
+ }
146
+
147
+
148
+ mode "migration_code" do
149
+ description "dump migration code on stdout"
150
+
151
+ def run
152
+ puts Bj.table.migration_code
153
+ end
154
+ end
155
+
156
+ mode "generate_migration" do
157
+ description "generate a migration"
158
+
159
+ def run
160
+ Bj.generate_migration
161
+ end
162
+ end
163
+
164
+ mode "migrate" do
165
+ description "migrate the db"
166
+
167
+ def run
168
+ Bj.migrate
169
+ end
170
+ end
171
+
172
+ mode "setup" do
173
+ description "generate a migration and migrate"
174
+
175
+ def run
176
+ Bj.setup
177
+ end
178
+ end
179
+
180
+ mode "run" do
181
+ description "start a job runnner, possibly as a daemon"
182
+
183
+ option("--forever"){}
184
+ option("--daemon"){}
185
+ option("--ppid"){
186
+ argument :required
187
+ cast :integer
188
+ }
189
+ option("--redirect"){
190
+ argument :required
191
+ }
192
+
193
+ def run
194
+ options = {}
195
+
196
+ %w[ forever daemon ppid ].each do |key|
197
+ options[key.to_sym] = true if param[key].given?
198
+ end
199
+
200
+ if param["redirect"].given?
201
+ open(param["redirect"].value, "a+") do |fd|
202
+ STDERR.reopen fd
203
+ STDOUT.reopen fd
204
+ end
205
+ STDERR.sync = true
206
+ STDOUT.sync = true
207
+ end
208
+
209
+ trap("SIGTERM"){
210
+ info{ "SIGTERM" }
211
+ exit
212
+ }
213
+
214
+ if param["daemon"].given?
215
+ daemon{ Bj.run options }
216
+ else
217
+ Bj.run options
218
+ end
219
+ end
220
+ end
221
+
222
+ mode "submit" do
223
+ keyword("file"){
224
+ argument :required
225
+ attr
226
+ }
227
+
228
+ def run
229
+ joblist = Bj.joblist.for argv.join(' ')
230
+
231
+ case file
232
+ when "-"
233
+ joblist.push(Bj.joblist.jobs_from_io(STDIN))
234
+ when "--", "---"
235
+ joblist.push(Bj.joblist.jobs_from_yaml(STDIN))
236
+ else
237
+ open(file){|io| joblist.push(Bj.joblist.jobs_from_io(io)) }
238
+ end
239
+
240
+ jobs = Bj.submit joblist, :no_tickle => true
241
+
242
+ oh = lambda{|job| OrderedHash["id", job.id, "command", job.command]}
243
+
244
+ y jobs.map{|job| oh[job]}
245
+ end
246
+ end
247
+
248
+ mode "list" do
249
+ def run
250
+ Bj.transaction do
251
+ y Bj::Table::Job.find(:all).map(&:to_hash)
252
+ end
253
+ end
254
+ end
255
+
256
+ mode "set" do
257
+ argument("key"){ attr }
258
+
259
+ argument("value"){ attr }
260
+
261
+ option("hostname", "H"){
262
+ argument :required
263
+ default Bj.hostname
264
+ attr
265
+ }
266
+
267
+ option("cast", "c"){
268
+ argument :required
269
+ default "to_s"
270
+ attr
271
+ }
272
+
273
+ def run
274
+ Bj.transaction do
275
+ Bj.config.set(key, value, :hostname => hostname, :cast => cast)
276
+ y Bj.table.config.for(:hostname => hostname)
277
+ end
278
+ end
279
+ end
280
+
281
+ mode "config" do
282
+ option("hostname", "H"){
283
+ argument :required
284
+ default Bj.hostname
285
+ }
286
+
287
+ def run
288
+ Bj.transaction do
289
+ y Bj.table.config.for(:hostname => param["hostname"].value)
290
+ end
291
+ end
292
+ end
293
+
294
+ mode "pid" do
295
+ option("hostname", "H"){
296
+ argument :required
297
+ default Bj.hostname
298
+ }
299
+
300
+ def run
301
+ Bj.transaction do
302
+ config = Bj.table.config.for(:hostname => param["hostname"].value)
303
+ puts config[ "#{ RAILS_ENV }.pid" ] if config
304
+ end
305
+ end
306
+ end
307
+
308
+
309
+ def run
310
+ help!
311
+ end
312
+
313
+ def before_run
314
+ self.logger = param["log"].value
315
+ Bj.logger = logger
316
+
317
+ if param["rails_root"].given?
318
+ rails_root = param["rails_root"].value
319
+ ENV["RAILS_ROOT"] = rails_root
320
+ ::Object.instance_eval do
321
+ remove_const :RAILS_ROOT
322
+ const_set :RAILS_ROOT, rails_root
323
+ end
324
+ end
325
+
326
+ if param["rails_env"].given?
327
+ rails_env = param["rails_env"].value
328
+ ENV["RAILS_ENV"] = rails_env
329
+ ::Object.instance_eval do
330
+ remove_const :RAILS_ENV
331
+ const_set :RAILS_ENV, rails_env
332
+ end
333
+ end
334
+ end
335
+
336
+ def daemon
337
+ ra, wa = IO.pipe
338
+ rb, wb = IO.pipe
339
+ if fork
340
+ at_exit{ exit! }
341
+ wa.close
342
+ r = ra
343
+ rb.close
344
+ w = wb
345
+ pid = r.gets
346
+ w.puts pid
347
+ Integer pid.strip
348
+ else
349
+ ra.close
350
+ w = wa
351
+ wb.close
352
+ r = rb
353
+ open("/dev/null", "r+") do |fd|
354
+ STDIN.reopen fd
355
+ STDOUT.reopen fd
356
+ STDERR.reopen fd
357
+ end
358
+ Process::setsid rescue nil
359
+ pid =
360
+ fork do
361
+ Dir::chdir RAILS_ROOT
362
+ File::umask 0
363
+ $DAEMON = true
364
+ yield
365
+ exit!
366
+ end
367
+ w.puts pid
368
+ r.gets
369
+ exit!
370
+ end
371
+ end
372
+ }
373
+
374
+
375
+
376
+
377
+
378
+ #
379
+ # we setup a few things so the script works regardless of whether it was
380
+ # called out of /usr/local/bin, ./script, or wherever. note that the script
381
+ # does *not* require the entire rails application to be loaded into memory!
382
+ # we could just load boot.rb and environment.rb, but this method let's
383
+ # submitting and running jobs be infinitely more lightweight.
384
+ #
385
+
386
+ BEGIN {
387
+ #
388
+ # see if we're running out of RAILS_ROOT/script/
389
+ #
390
+ unless defined? BJ_IS_SCRIPT #{{{
391
+ BJ_IS_SCRIPT =
392
+ if %w[ script config app ].map{|d| test ?d, "#{ File.dirname __FILE__ }/../#{ d }"}.all?
393
+ __FILE__
394
+ else
395
+ nil
396
+ end
397
+ end #}}}
398
+
399
+ #
400
+ # setup RAILS_ROOT
401
+ #
402
+ unless defined? RAILS_ROOT #{{{
403
+ ### grab env var first
404
+ rails_root = ENV["RAILS_ROOT"]
405
+
406
+ ### commandline usage clobbers
407
+ kv = nil
408
+ ARGV.delete_if{|arg| arg =~ %r/^RAILS_ROOT=/ and kv = arg}
409
+ rails_root = kv.split(%r/=/,2).last if kv
410
+
411
+ ### we know the rails_root if we are in RAILS_ROOT/script/
412
+ unless rails_root
413
+ if BJ_IS_SCRIPT
414
+ rails_root = File.expand_path "#{ File.dirname __FILE__ }/.."
415
+ end
416
+ end
417
+
418
+ ### perhaps the current directory is a rails_root?
419
+ unless rails_root
420
+ if %w[ script config app ].map{|d| test(?d, d)}.all?
421
+ rails_root = File.expand_path "."
422
+ end
423
+ end
424
+
425
+ ### bootstrap
426
+ RAILS_ROOT = rails_root
427
+ end #}}}
428
+
429
+ #
430
+ # setup RAILS_ENV
431
+ #
432
+ unless defined? RAILS_ENV #{{{
433
+ ### grab env var first
434
+ rails_env = ENV["RAILS_ENV"]
435
+
436
+ ### commandline usage clobbers
437
+ kv = nil
438
+ ARGV.delete_if{|arg| arg =~ %r/^RAILS_ENV=/ and kv = arg}
439
+ rails_env = kv.split(%r/=/,2).last if kv
440
+
441
+ ### fallback to development
442
+ unless rails_env
443
+ rails_env = "development"
444
+ end
445
+
446
+ ### bootstrap
447
+ RAILS_ENV = rails_env
448
+ end #}}}
449
+
450
+ #
451
+ # setup $LOAD_PATH to detect plugin - iff it is installed and running out of
452
+ # RAILS_ROOT/script
453
+ #
454
+ if RAILS_ROOT #{{{
455
+ if BJ_IS_SCRIPT and test(?d, "#{ RAILS_ROOT }/vendor/plugins/bj/lib")
456
+ $LOAD_PATH.unshift "#{ RAILS_ROOT }/vendor/plugins/bj/lib"
457
+ end
458
+ end #}}}
459
+
460
+ #
461
+ # ensure that rubygems is loaded
462
+ #
463
+ begin
464
+ require "rubygems"
465
+ rescue
466
+ 42
467
+ end
468
+
469
+ #
470
+ # hack to_s of STDERR/STDOUT for nice help messages
471
+ #
472
+ class << STDERR
473
+ def to_s() 'STDERR' end
474
+ end
475
+ class << STDOUT
476
+ def to_s() 'STDOUT' end
477
+ end
478
+ }