SciMed-bj 1.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +83 -0
- data/LICENSE +1 -0
- data/README +318 -0
- data/Rakefile +22 -0
- data/SciMed-bj.gemspec +77 -0
- data/TODO +53 -0
- data/VERSION +1 -0
- data/bin/bj +692 -0
- data/init.rb +1 -0
- data/install.rb +214 -0
- data/lib/bj.rb +85 -0
- data/lib/bj/api.rb +164 -0
- data/lib/bj/bj.rb +72 -0
- data/lib/bj/errors.rb +4 -0
- data/lib/bj/joblist.rb +112 -0
- data/lib/bj/logger.rb +51 -0
- data/lib/bj/runner.rb +369 -0
- data/lib/bj/stdext.rb +86 -0
- data/lib/bj/table.rb +426 -0
- data/lib/bj/util.rb +133 -0
- data/plugin/HISTORY +3 -0
- data/plugin/README +142 -0
- data/plugin/Rakefile +22 -0
- data/plugin/init.rb +33 -0
- data/plugin/install.rb +95 -0
- data/plugin/script/bj +55 -0
- data/plugin/tasks/bj_tasks.rake +4 -0
- data/plugin/test/bj_test.rb +8 -0
- data/plugin/uninstall.rb +1 -0
- data/todo.yml +23 -0
- metadata +149 -0
data/lib/bj/util.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
class Bj
|
2
|
+
module Util
|
3
|
+
module ModuleMethods
|
4
|
+
def constant_get const, &block
|
5
|
+
begin
|
6
|
+
ancestors = const.split(%r/::/)
|
7
|
+
parent = Object
|
8
|
+
while((child = ancestors.shift))
|
9
|
+
klass = parent.const_get child
|
10
|
+
parent = klass
|
11
|
+
end
|
12
|
+
klass
|
13
|
+
rescue
|
14
|
+
block ? block.call : raise
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def const_or_env const, &block
|
19
|
+
constant_get(const){ ENV[const] || block.call }
|
20
|
+
end
|
21
|
+
|
22
|
+
def spawn cmd, options = {}
|
23
|
+
options.to_options!
|
24
|
+
logger = options.has_key?(:logger) ? options[:logger] : Bj.logger
|
25
|
+
verbose = options.has_key? :verbose
|
26
|
+
logger.info{ "cmd <#{ cmd }>" } if logger
|
27
|
+
status = systemu cmd, 1=>(stdout=""), 2=>(stderr="")
|
28
|
+
logger.info{ "status <#{ status.exitstatus }>" } if logger
|
29
|
+
if verbose
|
30
|
+
if logger
|
31
|
+
if stdout.empty?
|
32
|
+
logger.info{ "stdout <>" }
|
33
|
+
else
|
34
|
+
logger.info{ "stdout <" }
|
35
|
+
logger << stdout.strip.gsub(%r/^/, ' ')
|
36
|
+
logger << "\n>\n"
|
37
|
+
end
|
38
|
+
if stderr.empty?
|
39
|
+
logger.info{ "stderr <>" }
|
40
|
+
else
|
41
|
+
logger.info{ "stderr <" }
|
42
|
+
logger << stderr.strip.gsub(%r/^/, ' ')
|
43
|
+
logger << "\n>\n"
|
44
|
+
end
|
45
|
+
else
|
46
|
+
STDOUT.puts stdout
|
47
|
+
STDERR.puts stderr
|
48
|
+
end
|
49
|
+
end
|
50
|
+
status.exitstatus.zero? or raise "#{ cmd.inspect } failed with #{ $?.inspect }"
|
51
|
+
[ stdout, stderr ]
|
52
|
+
end
|
53
|
+
|
54
|
+
def start *a
|
55
|
+
q = Queue.new
|
56
|
+
thread = Thread.new do
|
57
|
+
Thread.current.abort_on_exception = true
|
58
|
+
systemu(*a){|pid| q << pid}
|
59
|
+
end
|
60
|
+
pid = q.pop
|
61
|
+
thread.singleton_class{ define_method(:pid){ pid } }
|
62
|
+
thread
|
63
|
+
end
|
64
|
+
|
65
|
+
def alive pid
|
66
|
+
return false unless pid
|
67
|
+
pid = Integer pid.to_s
|
68
|
+
Process::kill 0, pid
|
69
|
+
true
|
70
|
+
rescue Errno::ESRCH, Errno::EPERM
|
71
|
+
false
|
72
|
+
end
|
73
|
+
alias_method "alive?", "alive"
|
74
|
+
|
75
|
+
def which_ruby
|
76
|
+
c = ::Config::CONFIG
|
77
|
+
ruby = File::join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
|
78
|
+
raise "ruby @ #{ ruby } not executable!?" unless test(?e, ruby)
|
79
|
+
ruby
|
80
|
+
end
|
81
|
+
|
82
|
+
def which_rake
|
83
|
+
tmp = Tempfile.new Process.pid
|
84
|
+
tmp.write "task(:foobar){ puts 42 }"
|
85
|
+
tmp.close
|
86
|
+
bat = spawn("rake.bat -f #{ tmp.path.inspect } foobar", :logger => false) rescue false
|
87
|
+
bat ? "rake.bat" : "rake"
|
88
|
+
ensure
|
89
|
+
tmp.close! rescue nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def ipc_signals_supported
|
93
|
+
@ipc_signals_supported ||=
|
94
|
+
IO.popen 'ruby', 'r+' do |ruby|
|
95
|
+
pid = ruby.pid
|
96
|
+
begin
|
97
|
+
Process.kill 'TERM', pid
|
98
|
+
true
|
99
|
+
rescue Exception
|
100
|
+
false
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
alias_method "ipc_signals_supported?", "ipc_signals_supported"
|
105
|
+
|
106
|
+
def find_script basename
|
107
|
+
path = ENV["PATH"] || ENV["path"] || Bj.default_path
|
108
|
+
raise "no env PATH" unless path
|
109
|
+
path = path.split File::PATH_SEPARATOR
|
110
|
+
path.unshift File.join(Bj.rails_root, "script")
|
111
|
+
path.each do |directory|
|
112
|
+
script = File.join directory, basename
|
113
|
+
return File.expand_path(script) if(test(?s, script) and test(?r, script))
|
114
|
+
end
|
115
|
+
raise "no #{ basename } found in #{ path.inspect }"
|
116
|
+
end
|
117
|
+
|
118
|
+
def valid_rails_root root = ".", expected = %w[ config script app ]
|
119
|
+
directories = expected.flatten.compact.map{|dir| dir.to_s}
|
120
|
+
directories.all?{|dir| test(?d, File.join(root, dir))}
|
121
|
+
end
|
122
|
+
alias_method "valid_rails_root?", "valid_rails_root"
|
123
|
+
|
124
|
+
def emsg e
|
125
|
+
m = e.message rescue ""
|
126
|
+
c = e.class rescue Exception
|
127
|
+
b = e.backtrace.join("\n") rescue ""
|
128
|
+
"#{ m }(#{ c })\n#{ b }"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
send :extend, ModuleMethods
|
132
|
+
end
|
133
|
+
end
|
data/plugin/HISTORY
ADDED
data/plugin/README
ADDED
@@ -0,0 +1,142 @@
|
|
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
|
+
1) $sudo gem install bj
|
57
|
+
2) add "require 'bj'" to config/environment.rb
|
58
|
+
3) bj setup
|
59
|
+
|
60
|
+
plugin:
|
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', :priority => 42
|
90
|
+
|
91
|
+
jobs = Bj.submit './script/runner ./scripts/a.rb', :rails_env => 'production'
|
92
|
+
|
93
|
+
jobs = Bj.submit './script/runner /dev/stdin',
|
94
|
+
:stdin => 'p RAILS_ENV',
|
95
|
+
:tag => 'dynamic ruby code'
|
96
|
+
|
97
|
+
jobs Bj.submit array_of_commands, :priority => 451
|
98
|
+
|
99
|
+
when jobs are run, they are run in RAILS_ROOT. various attributes are
|
100
|
+
available *only* once the job has finished. you can check whether or not a
|
101
|
+
job is finished by using the #finished method, which simple does a reload and
|
102
|
+
checks to see if the exit_status is non-nil.
|
103
|
+
|
104
|
+
eg:
|
105
|
+
|
106
|
+
jobs = Bj.submit list_of_jobs, :tag => 'important'
|
107
|
+
...
|
108
|
+
|
109
|
+
jobs.each do |job|
|
110
|
+
if job.finished?
|
111
|
+
p job.exit_status
|
112
|
+
p job.stdout
|
113
|
+
p job.stderr
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
See lib/bj/api.rb for more details.
|
118
|
+
|
119
|
+
________________________________
|
120
|
+
Sponsors
|
121
|
+
--------------------------------
|
122
|
+
http://www.engineyard.com/
|
123
|
+
http://quintess.com/
|
124
|
+
http://eparklabs.com/
|
125
|
+
|
126
|
+
PARAMETERS
|
127
|
+
--rails_root=rails_root, -R (0 ~> rails_root=)
|
128
|
+
the rails_root will be guessed unless you set this
|
129
|
+
--rails_env=rails_env, -E (0 ~> rails_env=development)
|
130
|
+
set the rails_env
|
131
|
+
--log=log, -l (0 ~> log=STDERR)
|
132
|
+
set the logfile
|
133
|
+
--help, -h
|
134
|
+
|
135
|
+
AUTHOR
|
136
|
+
ara.t.howard@gmail.com
|
137
|
+
|
138
|
+
URIS
|
139
|
+
http://codeforpeople.com/lib/ruby/
|
140
|
+
http://rubyforge.org/projects/codeforpeople/
|
141
|
+
http://codeforpeople.rubyforge.org/svn/rails/plugins/
|
142
|
+
|
data/plugin/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the bj plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the bj plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'Bj'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
data/plugin/init.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
dirname, basename = File.split(File.expand_path(__FILE__))
|
2
|
+
libdir = File.join dirname, "lib"
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift libdir
|
5
|
+
begin
|
6
|
+
require "bj"
|
7
|
+
ensure
|
8
|
+
$LOAD_PATH.shift
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
=begin
|
14
|
+
require "rubygems"
|
15
|
+
|
16
|
+
dir = Gem.dir
|
17
|
+
path = Gem.path
|
18
|
+
|
19
|
+
dirname, basename = File.split(File.expand_path(__FILE__))
|
20
|
+
gem_home = File.join dirname, "gem_home"
|
21
|
+
gem_path = [gem_home] #, *path]
|
22
|
+
|
23
|
+
Gem.send :use_paths, gem_home, gem_path
|
24
|
+
|
25
|
+
begin
|
26
|
+
%w[ attributes systemu orderedhash bj ].each do |lib|
|
27
|
+
gem lib
|
28
|
+
require lib
|
29
|
+
end
|
30
|
+
ensure
|
31
|
+
Gem.send :use_paths, dir, path
|
32
|
+
end
|
33
|
+
=end
|
data/plugin/install.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
dirname, basename = File.split File.expand_path(__FILE__)
|
4
|
+
|
5
|
+
libidr = 'lib'
|
6
|
+
bindir = 'bin'
|
7
|
+
gem_home = 'gem_home'
|
8
|
+
|
9
|
+
rails_root = File.expand_path File.join(dirname, '../../../')
|
10
|
+
bj = File.join rails_root, 'script', 'bj'
|
11
|
+
|
12
|
+
gems = %w[ attributes arrayfields main systemu orderedhash bj ]
|
13
|
+
|
14
|
+
# in the plugin dir...
|
15
|
+
Dir.chdir dirname do
|
16
|
+
puts "in #{ dirname }..."
|
17
|
+
|
18
|
+
# install gems locally
|
19
|
+
puts "installing #{ gems.join ' ' }..."
|
20
|
+
spawn "gem install #{ gems.join ' ' } --install-dir=#{ gem_home } --remote --force --include-dependencies --no-wrappers"
|
21
|
+
puts "."
|
22
|
+
|
23
|
+
=begin
|
24
|
+
=end
|
25
|
+
# copy libs over to libdir
|
26
|
+
glob = File.join gem_home, "gems/*/lib/*"
|
27
|
+
entries = Dir.glob glob
|
28
|
+
entries.each do |entry|
|
29
|
+
next if entry =~ %r/-\d+\.\d+\.\d+\.rb$/
|
30
|
+
src, dst = entry, libidr
|
31
|
+
puts "#{ src } -->> #{ dst }..."
|
32
|
+
FileUtils.cp_r src, dst
|
33
|
+
puts "."
|
34
|
+
end
|
35
|
+
|
36
|
+
# copy bins over to bindir
|
37
|
+
glob = File.join gem_home, "gems/*/bin/*"
|
38
|
+
entries = Dir.glob glob
|
39
|
+
entries.each do |entry|
|
40
|
+
next if entry =~ %r/-\d+\.\d+\.\d+\.rb$/
|
41
|
+
src, dst = entry, bindir
|
42
|
+
puts "#{ src } -->> #{ dst }..."
|
43
|
+
FileUtils.cp_r src, dst
|
44
|
+
puts "."
|
45
|
+
end
|
46
|
+
|
47
|
+
=begin
|
48
|
+
# copy gem_home/bj-x.x.x/bin/bj to rails_root/script/bj
|
49
|
+
glob = File.join gem_home, "gems/bj-*/bin/*"
|
50
|
+
srcs = Dir.glob glob
|
51
|
+
srcs.each do |src|
|
52
|
+
basename = File.basename src
|
53
|
+
dst = File.join rails_root, 'script', basename
|
54
|
+
puts "#{ src } -->> #{ dst }..."
|
55
|
+
FileUtils.cp_r src, dst
|
56
|
+
File.chmod 0755, dst
|
57
|
+
puts "."
|
58
|
+
end
|
59
|
+
=end
|
60
|
+
|
61
|
+
# install bin/bj to script/bj
|
62
|
+
src, dst = File.join(bindir, "bj"), File.join(rails_root, "script", "bj")
|
63
|
+
puts "#{ src } -->> #{ dst }..."
|
64
|
+
FileUtils.cp src, dst
|
65
|
+
File.chmod 0755, dst
|
66
|
+
puts "."
|
67
|
+
|
68
|
+
# kill all the local gems
|
69
|
+
FileUtils.rm_rf gem_home
|
70
|
+
|
71
|
+
# dump help
|
72
|
+
puts("=" * 79)
|
73
|
+
ruby = which_ruby
|
74
|
+
system "#{ ruby } #{ bj.inspect } '--help'"
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
BEGIN {
|
80
|
+
require 'fileutils'
|
81
|
+
require 'rbconfig'
|
82
|
+
|
83
|
+
def spawn command
|
84
|
+
oe = `#{ command } 2>&1`
|
85
|
+
raise "command <#{ command }> failed with <#{ $?.inspect }>" unless $?.exitstatus == 0
|
86
|
+
oe
|
87
|
+
end
|
88
|
+
|
89
|
+
def which_ruby
|
90
|
+
c = ::Config::CONFIG
|
91
|
+
ruby = File::join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
|
92
|
+
raise "ruby @ #{ ruby } not executable!?" unless test(?e, ruby)
|
93
|
+
ruby
|
94
|
+
end
|
95
|
+
}
|
data/plugin/script/bj
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'main'
|
4
|
+
require 'bj'
|
5
|
+
|
6
|
+
Main {
|
7
|
+
option('rails_root', 'R'){
|
8
|
+
argument_required
|
9
|
+
default '.'
|
10
|
+
}
|
11
|
+
|
12
|
+
option('rails_env', 'E'){
|
13
|
+
argument_required
|
14
|
+
default 'development'
|
15
|
+
}
|
16
|
+
|
17
|
+
def run
|
18
|
+
help!
|
19
|
+
end
|
20
|
+
|
21
|
+
mode 'setup' do
|
22
|
+
def run
|
23
|
+
bj.setup!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
mode 'test' do
|
28
|
+
def run
|
29
|
+
Bj.boot!
|
30
|
+
y Bj
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
mode 'migration' do
|
35
|
+
#puts Bj.migration
|
36
|
+
end
|
37
|
+
|
38
|
+
mode 'configure' do
|
39
|
+
end
|
40
|
+
|
41
|
+
mode 'submit' do
|
42
|
+
end
|
43
|
+
|
44
|
+
mode 'list' do
|
45
|
+
end
|
46
|
+
|
47
|
+
def bj
|
48
|
+
return @bj if defined? @bj
|
49
|
+
options = %w[
|
50
|
+
rails_root
|
51
|
+
rails_env
|
52
|
+
].inject(Hash.new){|h,k| h.update k => params[k].value}
|
53
|
+
@bj = Bj.new options.merge(:logger => logger)
|
54
|
+
end
|
55
|
+
}
|