ambethia-bj 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/HISTORY +80 -0
  2. data/LICENSE +1 -0
  3. data/README +318 -0
  4. data/Rakefile +20 -0
  5. data/TODO +53 -0
  6. data/VERSION +1 -0
  7. data/bin/bj +692 -0
  8. data/bj.gemspec +150 -0
  9. data/init.rb +1 -0
  10. data/install.rb +214 -0
  11. data/lib/bj.rb +85 -0
  12. data/lib/bj/api.rb +164 -0
  13. data/lib/bj/bj.rb +72 -0
  14. data/lib/bj/errors.rb +4 -0
  15. data/lib/bj/joblist.rb +112 -0
  16. data/lib/bj/logger.rb +50 -0
  17. data/lib/bj/runner.rb +330 -0
  18. data/lib/bj/stdext.rb +86 -0
  19. data/lib/bj/table.rb +426 -0
  20. data/lib/bj/util.rb +133 -0
  21. data/plugin/HISTORY +3 -0
  22. data/plugin/README +142 -0
  23. data/plugin/Rakefile +22 -0
  24. data/plugin/init.rb +33 -0
  25. data/plugin/install.rb +95 -0
  26. data/plugin/script/bj +55 -0
  27. data/plugin/tasks/bj_tasks.rake +4 -0
  28. data/plugin/test/bj_test.rb +8 -0
  29. data/plugin/uninstall.rb +1 -0
  30. data/spec/bj.rb +80 -0
  31. data/spec/helper.rb +85 -0
  32. data/spec/rails_root/README +256 -0
  33. data/spec/rails_root/Rakefile +10 -0
  34. data/spec/rails_root/app/controllers/application.rb +15 -0
  35. data/spec/rails_root/app/helpers/application_helper.rb +3 -0
  36. data/spec/rails_root/config/boot.rb +109 -0
  37. data/spec/rails_root/config/database.yml +23 -0
  38. data/spec/rails_root/config/environment.rb +67 -0
  39. data/spec/rails_root/config/environments/development.rb +17 -0
  40. data/spec/rails_root/config/environments/production.rb +22 -0
  41. data/spec/rails_root/config/environments/test.rb +22 -0
  42. data/spec/rails_root/config/initializers/inflections.rb +10 -0
  43. data/spec/rails_root/config/initializers/mime_types.rb +5 -0
  44. data/spec/rails_root/config/initializers/new_rails_defaults.rb +15 -0
  45. data/spec/rails_root/config/routes.rb +41 -0
  46. data/spec/rails_root/db/development.sqlite3 +0 -0
  47. data/spec/rails_root/db/migrate/20080909151517_bj_migration0.rb +8 -0
  48. data/spec/rails_root/db/schema.rb +62 -0
  49. data/spec/rails_root/doc/README_FOR_APP +2 -0
  50. data/spec/rails_root/log/development.log +141 -0
  51. data/spec/rails_root/log/production.log +0 -0
  52. data/spec/rails_root/log/server.log +0 -0
  53. data/spec/rails_root/log/test.log +0 -0
  54. data/spec/rails_root/public/404.html +30 -0
  55. data/spec/rails_root/public/422.html +30 -0
  56. data/spec/rails_root/public/500.html +30 -0
  57. data/spec/rails_root/public/dispatch.cgi +10 -0
  58. data/spec/rails_root/public/dispatch.fcgi +24 -0
  59. data/spec/rails_root/public/dispatch.rb +10 -0
  60. data/spec/rails_root/public/favicon.ico +0 -0
  61. data/spec/rails_root/public/images/rails.png +0 -0
  62. data/spec/rails_root/public/index.html +274 -0
  63. data/spec/rails_root/public/javascripts/application.js +2 -0
  64. data/spec/rails_root/public/javascripts/controls.js +963 -0
  65. data/spec/rails_root/public/javascripts/dragdrop.js +972 -0
  66. data/spec/rails_root/public/javascripts/effects.js +1120 -0
  67. data/spec/rails_root/public/javascripts/prototype.js +4225 -0
  68. data/spec/rails_root/public/robots.txt +5 -0
  69. data/spec/rails_root/script/about +3 -0
  70. data/spec/rails_root/script/bj +679 -0
  71. data/spec/rails_root/script/console +3 -0
  72. data/spec/rails_root/script/dbconsole +3 -0
  73. data/spec/rails_root/script/destroy +3 -0
  74. data/spec/rails_root/script/generate +3 -0
  75. data/spec/rails_root/script/performance/benchmarker +3 -0
  76. data/spec/rails_root/script/performance/profiler +3 -0
  77. data/spec/rails_root/script/performance/request +3 -0
  78. data/spec/rails_root/script/plugin +3 -0
  79. data/spec/rails_root/script/process/inspector +3 -0
  80. data/spec/rails_root/script/process/reaper +3 -0
  81. data/spec/rails_root/script/process/spawner +3 -0
  82. data/spec/rails_root/script/runner +3 -0
  83. data/spec/rails_root/script/server +3 -0
  84. data/spec/rails_root/test/test_helper.rb +38 -0
  85. data/todo.yml +23 -0
  86. metadata +184 -0
@@ -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
@@ -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
@@ -0,0 +1,4 @@
1
+ class Bj
2
+ class Error < ::StandardError; end
3
+ class RailsRoot < Error; end
4
+ end
@@ -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
@@ -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
@@ -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