SciMed-bj 1.2.4
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 +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
|
+
}
|