ambethia-bj 1.2.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 +80 -0
- data/LICENSE +1 -0
- data/README +318 -0
- data/Rakefile +20 -0
- data/TODO +53 -0
- data/VERSION +1 -0
- data/bin/bj +692 -0
- data/bj.gemspec +150 -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 +50 -0
- data/lib/bj/runner.rb +330 -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/spec/bj.rb +80 -0
- data/spec/helper.rb +85 -0
- data/spec/rails_root/README +256 -0
- data/spec/rails_root/Rakefile +10 -0
- data/spec/rails_root/app/controllers/application.rb +15 -0
- data/spec/rails_root/app/helpers/application_helper.rb +3 -0
- data/spec/rails_root/config/boot.rb +109 -0
- data/spec/rails_root/config/database.yml +23 -0
- data/spec/rails_root/config/environment.rb +67 -0
- data/spec/rails_root/config/environments/development.rb +17 -0
- data/spec/rails_root/config/environments/production.rb +22 -0
- data/spec/rails_root/config/environments/test.rb +22 -0
- data/spec/rails_root/config/initializers/inflections.rb +10 -0
- data/spec/rails_root/config/initializers/mime_types.rb +5 -0
- data/spec/rails_root/config/initializers/new_rails_defaults.rb +15 -0
- data/spec/rails_root/config/routes.rb +41 -0
- data/spec/rails_root/db/development.sqlite3 +0 -0
- data/spec/rails_root/db/migrate/20080909151517_bj_migration0.rb +8 -0
- data/spec/rails_root/db/schema.rb +62 -0
- data/spec/rails_root/doc/README_FOR_APP +2 -0
- data/spec/rails_root/log/development.log +141 -0
- data/spec/rails_root/log/production.log +0 -0
- data/spec/rails_root/log/server.log +0 -0
- data/spec/rails_root/log/test.log +0 -0
- data/spec/rails_root/public/404.html +30 -0
- data/spec/rails_root/public/422.html +30 -0
- data/spec/rails_root/public/500.html +30 -0
- data/spec/rails_root/public/dispatch.cgi +10 -0
- data/spec/rails_root/public/dispatch.fcgi +24 -0
- data/spec/rails_root/public/dispatch.rb +10 -0
- data/spec/rails_root/public/favicon.ico +0 -0
- data/spec/rails_root/public/images/rails.png +0 -0
- data/spec/rails_root/public/index.html +274 -0
- data/spec/rails_root/public/javascripts/application.js +2 -0
- data/spec/rails_root/public/javascripts/controls.js +963 -0
- data/spec/rails_root/public/javascripts/dragdrop.js +972 -0
- data/spec/rails_root/public/javascripts/effects.js +1120 -0
- data/spec/rails_root/public/javascripts/prototype.js +4225 -0
- data/spec/rails_root/public/robots.txt +5 -0
- data/spec/rails_root/script/about +3 -0
- data/spec/rails_root/script/bj +679 -0
- data/spec/rails_root/script/console +3 -0
- data/spec/rails_root/script/dbconsole +3 -0
- data/spec/rails_root/script/destroy +3 -0
- data/spec/rails_root/script/generate +3 -0
- data/spec/rails_root/script/performance/benchmarker +3 -0
- data/spec/rails_root/script/performance/profiler +3 -0
- data/spec/rails_root/script/performance/request +3 -0
- data/spec/rails_root/script/plugin +3 -0
- data/spec/rails_root/script/process/inspector +3 -0
- data/spec/rails_root/script/process/reaper +3 -0
- data/spec/rails_root/script/process/spawner +3 -0
- data/spec/rails_root/script/runner +3 -0
- data/spec/rails_root/script/server +3 -0
- data/spec/rails_root/test/test_helper.rb +38 -0
- data/todo.yml +23 -0
- metadata +184 -0
data/lib/bj/api.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
class Bj
|
2
|
+
#
|
3
|
+
# the api exposes nearly all the bj code you'll likely need, with the
|
4
|
+
# exception of accessing the job table for searching, which is done using
|
5
|
+
#
|
6
|
+
# eg.
|
7
|
+
#
|
8
|
+
# Bj.table.job.find :all
|
9
|
+
#
|
10
|
+
module API
|
11
|
+
#
|
12
|
+
# submit jobs for background processing. 'jobs' can be a string or array of
|
13
|
+
# strings. options are applied to each job in the 'jobs', and the list of
|
14
|
+
# submitted jobs is always returned. options (string or symbol) can be
|
15
|
+
#
|
16
|
+
# :rails_env => production|development|key_in_database_yml
|
17
|
+
# when given this keyword causes bj to submit jobs to the
|
18
|
+
# specified database. default is RAILS_ENV.
|
19
|
+
#
|
20
|
+
# :priority => any number, including negative ones. default is zero.
|
21
|
+
#
|
22
|
+
# :tag => a tag added to the job. simply makes searching easier.
|
23
|
+
#
|
24
|
+
# :env => a hash specifying any additional environment vars the background
|
25
|
+
# process should have.
|
26
|
+
#
|
27
|
+
# :stdin => any stdin the background process should have.
|
28
|
+
#
|
29
|
+
# eg:
|
30
|
+
#
|
31
|
+
# jobs = Bj.submit 'echo foobar', :tag => 'simple job'
|
32
|
+
#
|
33
|
+
# jobs = Bj.submit '/bin/cat', :stdin => 'in the hat', :priority => 42
|
34
|
+
#
|
35
|
+
# jobs = Bj.submit './script/runner ./scripts/a.rb', :rails_env => 'production'
|
36
|
+
#
|
37
|
+
# jobs = Bj.submit './script/runner /dev/stdin', :stdin => 'p RAILS_ENV', :tag => 'dynamic ruby code'
|
38
|
+
#
|
39
|
+
# jobs = Bj.submit array_of_commands, :priority => 451
|
40
|
+
#
|
41
|
+
# when jobs are run, they are run in RAILS_ROOT. various attributes are
|
42
|
+
# available *only* once the job has finished. you can check whether or not
|
43
|
+
# a job is finished by using the #finished method, which simple does a
|
44
|
+
# reload and checks to see if the exit_status is non-nil.
|
45
|
+
#
|
46
|
+
# eg:
|
47
|
+
#
|
48
|
+
# jobs = Bj.submit list_of_jobs, :tag => 'important'
|
49
|
+
# ...
|
50
|
+
#
|
51
|
+
# jobs.each do |job|
|
52
|
+
# if job.finished?
|
53
|
+
# p job.exit_status
|
54
|
+
# p job.stdout
|
55
|
+
# p job.stderr
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
#
|
60
|
+
def submit jobs, options = {}, &block
|
61
|
+
options.to_options!
|
62
|
+
Bj.transaction(options) do
|
63
|
+
table.job.submit jobs, options, &block
|
64
|
+
end
|
65
|
+
ensure
|
66
|
+
Bj.runner.tickle unless options[:no_tickle]
|
67
|
+
end
|
68
|
+
#
|
69
|
+
# this method changes the context under which bj is operating. a context is
|
70
|
+
# a RAILS_ENV. the method accepts a block and it used to alter the
|
71
|
+
# behaviour of the bj lib on a global scale such that all operations,
|
72
|
+
# spawning of background runnner processes, etc, occur in that context.
|
73
|
+
#
|
74
|
+
# eg:
|
75
|
+
#
|
76
|
+
# Bj.in :production do
|
77
|
+
# Bj.submit './script/runner ./scripts/facebook_notification.rb'
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# Bj.in :development do
|
81
|
+
# Bj.submit 'does_this_eat_memory.exe'
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
def in rails_env = Bj.rails_env, &block
|
85
|
+
transaction(:rails_env => rails_env.to_s, &block)
|
86
|
+
end
|
87
|
+
#
|
88
|
+
# list simply returns a list of all jobs in the job table
|
89
|
+
#
|
90
|
+
def list options = {}, &block
|
91
|
+
options.to_options!
|
92
|
+
Bj.transaction(options) do
|
93
|
+
options.delete :rails_env
|
94
|
+
table.job.find(:all, options)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
#
|
98
|
+
#
|
99
|
+
#
|
100
|
+
def run options = {}
|
101
|
+
runner.run options
|
102
|
+
end
|
103
|
+
#
|
104
|
+
# generate a migration and migrate a database (production/development/etc)
|
105
|
+
#
|
106
|
+
def setup options = {}
|
107
|
+
options.to_options!
|
108
|
+
chroot do
|
109
|
+
generate_migration options
|
110
|
+
migrate options
|
111
|
+
end
|
112
|
+
end
|
113
|
+
#
|
114
|
+
# generate_migration, suprisingly, generates the single migration needed for
|
115
|
+
# bj. you'll notice the the migration is very short as the migration
|
116
|
+
# classes themselves are inner classes of the respective bj table class.
|
117
|
+
# see lib/bj/table.rb for details.
|
118
|
+
#
|
119
|
+
def generate_migration options = {}
|
120
|
+
options.to_options!
|
121
|
+
options[:verbose] = true
|
122
|
+
chroot do
|
123
|
+
before = Dir.glob "./db/migrate/*"
|
124
|
+
n = Dir.glob("./db/migrate/*_bj_*").size
|
125
|
+
classname = "BjMigration#{ n }"
|
126
|
+
util.spawn "#{ Bj.ruby } ./script/generate migration #{ classname }", options rescue nil
|
127
|
+
after = Dir.glob "./db/migrate/*"
|
128
|
+
candidates = after - before
|
129
|
+
case candidates.size
|
130
|
+
when 0
|
131
|
+
false
|
132
|
+
when 1
|
133
|
+
generated = candidates.first
|
134
|
+
open(generated, "w"){|fd| fd.puts Bj.table.migration_code(classname)}
|
135
|
+
Bj.logger.info{ "generated <#{ generated }>" }
|
136
|
+
generated
|
137
|
+
else
|
138
|
+
raise "ambiguous migration <#{ candidates.inspect }>"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
#
|
143
|
+
# migrate a database (production|development|etc)
|
144
|
+
#
|
145
|
+
def migrate options = {}
|
146
|
+
options.to_options!
|
147
|
+
options[:verbose] = true
|
148
|
+
chroot do
|
149
|
+
util.spawn "#{ Bj.rake } RAILS_ENV=#{ Bj.rails_env } db:migrate", options
|
150
|
+
end
|
151
|
+
end
|
152
|
+
#
|
153
|
+
# install plugin into this rails app
|
154
|
+
#
|
155
|
+
def plugin options = {}
|
156
|
+
options.to_options!
|
157
|
+
options[:verbose] = true
|
158
|
+
chroot do
|
159
|
+
util.spawn "#{ Bj.ruby } ./script/plugin install http://codeforpeople.rubyforge.org/svn/rails/plugins/bj --force", options
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
send :extend, API
|
164
|
+
end
|
data/lib/bj/bj.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
class Bj
|
2
|
+
module ClassMethods
|
3
|
+
fattr("rails_root"){ Util.const_or_env("RAILS_ROOT"){ "." } }
|
4
|
+
fattr("rails_env"){ Util.const_or_env("RAILS_ENV"){ "development" } }
|
5
|
+
fattr("database_yml"){ File.join rails_root, "config", "database.yml" }
|
6
|
+
fattr("configurations"){ YAML::load(ERB.new(IO.read(database_yml)).result) }
|
7
|
+
fattr("tables"){ Table.list }
|
8
|
+
fattr("hostname"){ Socket.gethostname }
|
9
|
+
fattr("logger"){ Bj::Logger.off STDERR }
|
10
|
+
fattr("ruby"){ Util.which_ruby }
|
11
|
+
fattr("rake"){ Util.which_rake }
|
12
|
+
fattr("script"){ Util.find_script "bj" }
|
13
|
+
fattr("ttl"){ Integer(Bj::Table::Config["ttl"] || (twenty_four_hours = 24 * 60 * 60)) }
|
14
|
+
fattr("table"){ Table }
|
15
|
+
fattr("config"){ table.config }
|
16
|
+
fattr("util"){ Util }
|
17
|
+
fattr("runner"){ Runner }
|
18
|
+
fattr("joblist"){ Joblist }
|
19
|
+
fattr("default_path"){ %w'/bin /usr/bin /usr/local/bin /opt/local/bin'.join(File::PATH_SEPARATOR) }
|
20
|
+
|
21
|
+
def transaction options = {}, &block
|
22
|
+
options.to_options!
|
23
|
+
|
24
|
+
cur_rails_env = Bj.rails_env.to_s
|
25
|
+
new_rails_env = options[:rails_env].to_s
|
26
|
+
|
27
|
+
cur_spec = configurations[cur_rails_env]
|
28
|
+
table.establish_connection(cur_spec) unless table.connected?
|
29
|
+
|
30
|
+
if(new_rails_env.empty? or cur_rails_env == new_rails_env)
|
31
|
+
table.transaction{ block.call(table.connection) }
|
32
|
+
else
|
33
|
+
new_spec = configurations[new_rails_env]
|
34
|
+
table.establish_connection(new_spec)
|
35
|
+
Bj.rails_env = new_rails_env
|
36
|
+
begin
|
37
|
+
table.transaction{ block.call(table.connection) }
|
38
|
+
ensure
|
39
|
+
table.establish_connection(cur_spec)
|
40
|
+
Bj.rails_env = cur_rails_env
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def chroot options = {}, &block
|
46
|
+
if defined? @chrooted and @chrooted
|
47
|
+
return(block ? block.call(@chrooted) : @chrooted)
|
48
|
+
end
|
49
|
+
if block
|
50
|
+
begin
|
51
|
+
chrooted = @chrooted
|
52
|
+
Dir.chdir(@chrooted = rails_root) do
|
53
|
+
raise RailsRoot, "<#{ Dir.pwd }> is not a rails root" unless Util.valid_rails_root?(Dir.pwd)
|
54
|
+
block.call(@chrooted)
|
55
|
+
end
|
56
|
+
ensure
|
57
|
+
@chrooted = chrooted
|
58
|
+
end
|
59
|
+
else
|
60
|
+
Dir.chdir(@chrooted = rails_root)
|
61
|
+
raise RailsRoot, "<#{ Dir.pwd }> is not a rails root" unless Util.valid_rails_root?(Dir.pwd)
|
62
|
+
@chrooted
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def boot
|
67
|
+
load File.join(rails_root, "config", "boot.rb")
|
68
|
+
load File.join(rails_root, "config", "environment.rb")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
send :extend, ClassMethods
|
72
|
+
end
|
data/lib/bj/errors.rb
ADDED
data/lib/bj/joblist.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
class Bj
|
2
|
+
class JobList < ::Array
|
3
|
+
module ClassMethods
|
4
|
+
def for jobs, options = {}
|
5
|
+
if Joblist === jobs
|
6
|
+
jobs.update options
|
7
|
+
return jobs
|
8
|
+
end
|
9
|
+
options.to_options!
|
10
|
+
jobs = [jobs].flatten.compact
|
11
|
+
list = []
|
12
|
+
jobs.each do |arg|
|
13
|
+
list.push(
|
14
|
+
case arg
|
15
|
+
when String
|
16
|
+
case arg
|
17
|
+
when %r/^\d+$/
|
18
|
+
job_from_id arg
|
19
|
+
else
|
20
|
+
job_from_string arg
|
21
|
+
end
|
22
|
+
when Hash
|
23
|
+
job_from_hash arg
|
24
|
+
when Io
|
25
|
+
jobs_from_io arg
|
26
|
+
when Fixnum, Bignum
|
27
|
+
job_from_number arg
|
28
|
+
else
|
29
|
+
job_from_string arg
|
30
|
+
end
|
31
|
+
)
|
32
|
+
end
|
33
|
+
list.flatten!
|
34
|
+
list.compact!
|
35
|
+
list.map!{|job| job.reverse_merge! options}
|
36
|
+
list
|
37
|
+
end
|
38
|
+
|
39
|
+
def job_from_hash arg
|
40
|
+
arg.to_hash.to_options!
|
41
|
+
end
|
42
|
+
|
43
|
+
def job_from_string arg
|
44
|
+
unless arg.strip.empty?
|
45
|
+
{ :command => arg.to_s }
|
46
|
+
else
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def job_from_number arg
|
52
|
+
id = arg.to_i
|
53
|
+
Table::Job.find(id).to_hash
|
54
|
+
end
|
55
|
+
|
56
|
+
def jobs_from_io arg
|
57
|
+
if arg == "-"
|
58
|
+
load_from_io STDIN
|
59
|
+
else
|
60
|
+
if arg.respond_to? :read
|
61
|
+
load_from_io arg
|
62
|
+
else
|
63
|
+
open(arg, "r"){|fd| load_from_io fd}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def load_from_io io
|
69
|
+
list = []
|
70
|
+
io.each do |line|
|
71
|
+
line.strip!
|
72
|
+
next if line.empty?
|
73
|
+
list << job_from_string(line)
|
74
|
+
end
|
75
|
+
list
|
76
|
+
end
|
77
|
+
|
78
|
+
def jobs_from_yaml arg
|
79
|
+
object =
|
80
|
+
if arg == "-"
|
81
|
+
YAML.load STDIN
|
82
|
+
else
|
83
|
+
if arg.respond_to? :read
|
84
|
+
YAML.load arg
|
85
|
+
else
|
86
|
+
open(arg, "r"){|fd| YAML.load fd}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
Joblist.for object
|
90
|
+
end
|
91
|
+
end
|
92
|
+
send :extend, ClassMethods
|
93
|
+
|
94
|
+
module InstanceMethods
|
95
|
+
def update options = {}
|
96
|
+
options.to_options!
|
97
|
+
each{|job| job.update options}
|
98
|
+
end
|
99
|
+
|
100
|
+
def push other
|
101
|
+
Joblist.for(other).each do |job|
|
102
|
+
super job
|
103
|
+
end
|
104
|
+
self
|
105
|
+
end
|
106
|
+
alias_method "<<", "push"
|
107
|
+
end
|
108
|
+
send :include, InstanceMethods
|
109
|
+
end
|
110
|
+
|
111
|
+
Joblist = JobList
|
112
|
+
end
|
data/lib/bj/logger.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
class Bj
|
2
|
+
class Logger < ::Logger
|
3
|
+
def self.new *a, &b
|
4
|
+
super(*a, &b).instance_eval{ @default_formatter = @formatter = Formatter.new; self }
|
5
|
+
end
|
6
|
+
def format_message(severity, datetime, progname, msg)
|
7
|
+
(@formatter || @default_formatter).call(severity, datetime, progname, msg)
|
8
|
+
end
|
9
|
+
|
10
|
+
def device
|
11
|
+
@logdev.instance_eval{ @dev }
|
12
|
+
end
|
13
|
+
|
14
|
+
def tty?
|
15
|
+
device.respond_to?('tty?') and device.tty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def turn which
|
19
|
+
@logdev.extend OnOff unless OnOff === @logdev
|
20
|
+
@logdev.turn which
|
21
|
+
end
|
22
|
+
|
23
|
+
module OnOff
|
24
|
+
def turn which
|
25
|
+
@turned = which.to_s =~ %r/on/i ? :on : :off
|
26
|
+
end
|
27
|
+
|
28
|
+
def write message
|
29
|
+
return message.to_s.size if @turned == :off
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def on
|
35
|
+
turn :on
|
36
|
+
end
|
37
|
+
alias_method "on!", "on"
|
38
|
+
def self.on *a, &b
|
39
|
+
new(*a, &b).instance_eval{ turn :on; self }
|
40
|
+
end
|
41
|
+
|
42
|
+
def off
|
43
|
+
turn :off
|
44
|
+
end
|
45
|
+
alias_method "off!", "off"
|
46
|
+
def self.off *a, &b
|
47
|
+
new(*a, &b).instance_eval{ turn :off; self }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/bj/runner.rb
ADDED
@@ -0,0 +1,330 @@
|
|
1
|
+
class Bj
|
2
|
+
class Runner
|
3
|
+
class Background
|
4
|
+
def self.for(*a, &b) new(*a, &b) end
|
5
|
+
|
6
|
+
fattr("command"){}
|
7
|
+
fattr("thread"){}
|
8
|
+
fattr("pid"){}
|
9
|
+
|
10
|
+
def initialize command
|
11
|
+
@command = command
|
12
|
+
@thread = new_thread
|
13
|
+
end
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
{
|
17
|
+
"command" => command,
|
18
|
+
"pid" => pid,
|
19
|
+
}.inspect
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# TODO - auto start runner?
|
24
|
+
|
25
|
+
def new_thread
|
26
|
+
this = self
|
27
|
+
Thread.new do
|
28
|
+
Thread.current.abort_on_exception = true
|
29
|
+
loop do
|
30
|
+
cleanup = lambda{}
|
31
|
+
|
32
|
+
IO.popen command, "r+" do |pipe|
|
33
|
+
this.pid = pid = pipe.pid
|
34
|
+
cleanup = lambda do
|
35
|
+
cleanup = lambda{}
|
36
|
+
begin; Process.kill(Runner.kill_signal, pid); rescue Exception; 42; end
|
37
|
+
end
|
38
|
+
at_exit &cleanup
|
39
|
+
Process.wait
|
40
|
+
end
|
41
|
+
|
42
|
+
Bj.logger.error{ "#{ command } failed with #{ $?.inspect }" } unless
|
43
|
+
[0, 42].include?($?.exitstatus)
|
44
|
+
|
45
|
+
cleanup.call
|
46
|
+
|
47
|
+
sleep 42
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module ClassMethods
|
54
|
+
fattr("thread"){ Thread.current }
|
55
|
+
fattr("hup_signal"){ Signal.list.keys.index("HUP") ? "HUP" : "ABRT" }
|
56
|
+
fattr("hup_signaled"){ false }
|
57
|
+
fattr("kill_signal"){ "TERM" }
|
58
|
+
fattr("kill_signaled"){ false }
|
59
|
+
|
60
|
+
def tickle
|
61
|
+
return nil if Bj.config[Runner.no_tickle_key]
|
62
|
+
ping or start
|
63
|
+
end
|
64
|
+
|
65
|
+
def ping
|
66
|
+
begin
|
67
|
+
pid = nil
|
68
|
+
uri = nil
|
69
|
+
process = nil
|
70
|
+
Bj.transaction do
|
71
|
+
pid = Bj.config[Runner.key(Process.pid)] || Bj.config[Runner.key]
|
72
|
+
uri = Bj.config["#{ pid }.uri"]
|
73
|
+
process =
|
74
|
+
if uri
|
75
|
+
require "drb"
|
76
|
+
# DRb.start_service "druby://localhost:0"
|
77
|
+
DRbObject.new(nil, uri)
|
78
|
+
else
|
79
|
+
Process
|
80
|
+
end
|
81
|
+
end
|
82
|
+
return nil unless pid
|
83
|
+
pid = Integer pid
|
84
|
+
begin
|
85
|
+
process.kill Runner.hup_signal, pid
|
86
|
+
pid
|
87
|
+
rescue Exception => e
|
88
|
+
false
|
89
|
+
end
|
90
|
+
rescue Exception => e
|
91
|
+
false
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def key ppid = 0
|
96
|
+
ppid ||= 0
|
97
|
+
#"#{ Bj.rails_env }.#{ ppid }.pid"
|
98
|
+
"runner.#{ ppid }.pid"
|
99
|
+
end
|
100
|
+
|
101
|
+
def no_tickle_key
|
102
|
+
# "#{ Bj.rails_env }.no_tickle"
|
103
|
+
"no_tickle"
|
104
|
+
end
|
105
|
+
|
106
|
+
def start options = {}
|
107
|
+
options.to_options!
|
108
|
+
background.delete Bj.rails_env if options[:force]
|
109
|
+
background[Bj.rails_env] ||= Background.for(command)
|
110
|
+
end
|
111
|
+
|
112
|
+
def background
|
113
|
+
@background ||= Hash.new
|
114
|
+
end
|
115
|
+
|
116
|
+
def background= value
|
117
|
+
@background ||= value
|
118
|
+
end
|
119
|
+
|
120
|
+
def command
|
121
|
+
"#{ Bj.ruby } " + %W[
|
122
|
+
#{ Bj.script }
|
123
|
+
run
|
124
|
+
--forever
|
125
|
+
--redirect=#{ log }
|
126
|
+
--ppid=#{ Process.pid }
|
127
|
+
--rails_env=#{ Bj.rails_env }
|
128
|
+
--rails_root=#{ Bj.rails_root }
|
129
|
+
].map{|word| word.inspect}.join(" ")
|
130
|
+
end
|
131
|
+
|
132
|
+
def log
|
133
|
+
File.join logdir, "bj.#{ Bj.hostname }.#{ Bj.rails_env }.log"
|
134
|
+
end
|
135
|
+
|
136
|
+
def logdir
|
137
|
+
File.join File.expand_path(Bj.rails_root), 'log'
|
138
|
+
end
|
139
|
+
|
140
|
+
def run options = {}, &block
|
141
|
+
new(options, &block).run
|
142
|
+
end
|
143
|
+
end
|
144
|
+
send :extend, ClassMethods
|
145
|
+
|
146
|
+
module Instance_Methods
|
147
|
+
fattr("options"){}
|
148
|
+
fattr("block"){}
|
149
|
+
|
150
|
+
def initialize options = {}, &block
|
151
|
+
options.to_options!
|
152
|
+
@options, @block = options, block
|
153
|
+
end
|
154
|
+
|
155
|
+
def run
|
156
|
+
wait = options[:wait] || 42
|
157
|
+
limit = options[:limit]
|
158
|
+
forever = options[:forever]
|
159
|
+
|
160
|
+
limit = false if forever
|
161
|
+
wait = Integer wait
|
162
|
+
loopno = 0
|
163
|
+
|
164
|
+
Runner.thread = Thread.current
|
165
|
+
Bj.chroot
|
166
|
+
|
167
|
+
register or exit!(EXIT::WARNING)
|
168
|
+
|
169
|
+
Bj.logger.info{ "STARTED" }
|
170
|
+
at_exit{ Bj.logger.info{ "STOPPED" } }
|
171
|
+
|
172
|
+
fill_morgue
|
173
|
+
install_signal_handlers
|
174
|
+
|
175
|
+
loop do
|
176
|
+
ping_parent
|
177
|
+
|
178
|
+
loopno += 1
|
179
|
+
break if(limit and loopno > limit)
|
180
|
+
|
181
|
+
archive_jobs
|
182
|
+
|
183
|
+
catch :no_jobs do
|
184
|
+
loop do
|
185
|
+
job = thread = stdout = stderr = nil
|
186
|
+
|
187
|
+
Bj.transaction(options) do
|
188
|
+
now = Time.now.utc
|
189
|
+
|
190
|
+
job = Bj::Table::Job.find :first,
|
191
|
+
:conditions => ["state = ? and submitted_at <= ?", "pending", now],
|
192
|
+
:order => "priority DESC, submitted_at ASC",
|
193
|
+
:limit => 1,
|
194
|
+
:lock => true
|
195
|
+
throw :no_jobs unless job
|
196
|
+
|
197
|
+
Bj.logger.info{ "#{ job.title } - starting..." }
|
198
|
+
end
|
199
|
+
|
200
|
+
job.run!
|
201
|
+
|
202
|
+
Bj.logger.info{ "#{ job.title } - exit_status=#{ job.exit_status }" }
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
Runner.hup_signaled false
|
207
|
+
wait.times do
|
208
|
+
break if Runner.hup_signaled?
|
209
|
+
break if Runner.kill_signaled?
|
210
|
+
sleep 1
|
211
|
+
end
|
212
|
+
|
213
|
+
break unless(limit or limit == false)
|
214
|
+
break if Runner.kill_signaled?
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def ping_parent
|
219
|
+
ppid = options[:ppid]
|
220
|
+
return unless ppid
|
221
|
+
begin
|
222
|
+
Process.kill 0, Integer(ppid)
|
223
|
+
rescue Errno::ESRCH
|
224
|
+
Kernel.exit 42
|
225
|
+
rescue Exception
|
226
|
+
42
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def install_signal_handlers
|
231
|
+
Runner.hup_signaled false
|
232
|
+
hup_handler = nil
|
233
|
+
hup_handler =
|
234
|
+
trap Runner.hup_signal do |*a|
|
235
|
+
begin
|
236
|
+
Runner.hup_signaled true
|
237
|
+
rescue Exception => e
|
238
|
+
Bj.logger.error{ e } rescue nil
|
239
|
+
end
|
240
|
+
hup_handler.call *a rescue nil
|
241
|
+
end
|
242
|
+
|
243
|
+
Runner.kill_signaled false
|
244
|
+
kill_handler = nil
|
245
|
+
kill_handler =
|
246
|
+
trap Runner.kill_signal do |*a|
|
247
|
+
begin
|
248
|
+
Runner.kill_signaled true
|
249
|
+
rescue Exception => e
|
250
|
+
Bj.logger.error{ e } rescue nil
|
251
|
+
end
|
252
|
+
kill_handler.call *a rescue nil
|
253
|
+
end
|
254
|
+
|
255
|
+
begin
|
256
|
+
trap("INT"){ exit }
|
257
|
+
rescue Exception
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def fill_morgue
|
262
|
+
Bj.transaction do
|
263
|
+
now = Time.now.utc
|
264
|
+
jobs = Bj::Table::Job.find :all,
|
265
|
+
:conditions => ["state = 'running' and runner = ?", Bj.hostname]
|
266
|
+
jobs.each do |job|
|
267
|
+
if job.is_restartable?
|
268
|
+
Bj.logger.info{ "#{ job.title } - found dead and bloated but resubmitted" }
|
269
|
+
%w[ runner pid started_at finished_at stdout stderr exit_status ].each do |column|
|
270
|
+
job[column] = nil
|
271
|
+
end
|
272
|
+
job.state = 'pending'
|
273
|
+
else
|
274
|
+
Bj.logger.info{ "#{ job.title } - found dead and bloated" }
|
275
|
+
job.state = 'dead'
|
276
|
+
job.finished_at = now
|
277
|
+
end
|
278
|
+
job.save!
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def archive_jobs
|
284
|
+
Bj.transaction do
|
285
|
+
now = Time.now.utc
|
286
|
+
too_old = now - Bj.ttl
|
287
|
+
jobs = Bj::Table::Job.find :all,
|
288
|
+
:conditions => ["(state = 'finished' or state = 'dead') and submitted_at < ?", too_old]
|
289
|
+
jobs.each do |job|
|
290
|
+
Bj.logger.info{ "#{ job.title } - archived" }
|
291
|
+
hash = job.to_hash.update(:archived_at => now)
|
292
|
+
Bj::Table::JobArchive.create! hash
|
293
|
+
job.destroy
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def register
|
299
|
+
Bj.transaction do
|
300
|
+
pid = Bj.config[key]
|
301
|
+
return false if Util.alive?(pid)
|
302
|
+
Bj.config[key] = Process.pid
|
303
|
+
unless Bj.util.ipc_signals_supported? # not winblows
|
304
|
+
require "drb"
|
305
|
+
DRb.start_service "druby://localhost:0", Process
|
306
|
+
Bj.config["#{ Process.pid }.uri"] = DRb.uri
|
307
|
+
end
|
308
|
+
end
|
309
|
+
at_exit{ unregister }
|
310
|
+
true
|
311
|
+
rescue Exception
|
312
|
+
false
|
313
|
+
end
|
314
|
+
|
315
|
+
def unregister
|
316
|
+
Bj.transaction do
|
317
|
+
Bj.config.delete key
|
318
|
+
end
|
319
|
+
true
|
320
|
+
rescue Exception
|
321
|
+
false
|
322
|
+
end
|
323
|
+
|
324
|
+
def key
|
325
|
+
@key ||= ( options[:ppid] ? Runner.key(options[:ppid]) : Runner.key )
|
326
|
+
end
|
327
|
+
end
|
328
|
+
send :include, Instance_Methods
|
329
|
+
end
|
330
|
+
end
|