SciMed-bj 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY ADDED
@@ -0,0 +1,83 @@
1
+ 1.2.1
2
+ - Vibes fix for Ruby 1.8.7 and new Rakefile to make building the gem easier
3
+
4
+ 1.2.0
5
+ - fixes to docs
6
+ - added license
7
+ - factored out job running logic into job.run(), for testing
8
+ - added some specs. gasp.
9
+
10
+ 1.0.3
11
+ - env wasn't properly unpacked by runner, added YAML.load(job.env), thanks
12
+ Chris Wanstrath
13
+ - made operations that generate migrations, etc, verbose - they dump
14
+ stdout and stderr to console when running
15
+
16
+ 1.0.2:
17
+ - Bj now (should) auto detect the correct rake command on windows as
18
+ "rake.bat" not "rake". see Bj.which_rake and Bj.rake for impl.
19
+
20
+ 1.0.1:
21
+ - fixed name collision with 'record.attributes = hash' ar mass
22
+ assignment method (thx jon guymon)
23
+ - added new sponsor: http://igicom.com/
24
+
25
+ 0.0.5:
26
+ - use full path to ruby for plugin mode
27
+ - plugin correctly installs bin -->> script
28
+ - plugin install uses --force
29
+ - properly quote paths in windows (spaces)
30
+ - switch win signal to ABRT (was INT)
31
+ - background job regrestration now uses ppid to pin the subprocess to a
32
+ parent
33
+ - use ppid to detect parent death and exit in event loop
34
+ - don't use gem dependanices in plugin as they are broken when loading from
35
+ muliple gem repos
36
+ - added a small amount of drb magic that allows signals to work across
37
+ processes even on windows (see http://drawohara.com/post/22540307)
38
+
39
+ 0.0.4:
40
+ - basic functionality in windows
41
+ - several small bug fixes
42
+
43
+ 0.0.3:
44
+ - *many* small bug fixes
45
+
46
+ - plugin install should now pick up dependancies from plugin dir, last
47
+ release had LOAD_PATH/gem issues and was picking up globally installed
48
+ gems
49
+
50
+ - automatic management of the background processing can be turned off if you
51
+ want to manage your own processes
52
+
53
+ - all jobs are automatically restartable unless submitted with
54
+
55
+ :restartable => false
56
+
57
+ this means that, should a runner ever die, upon restart any jobs that were
58
+ mid-process will automatically be restarted
59
+
60
+ - signal based parent lifeline move out of thread and into even loop
61
+
62
+ - :lock => true added to a few AR finds to support true write serializable
63
+ transaction isolation when the db supports it
64
+
65
+ - all migrations now use :force => true and
66
+
67
+ - running 'bj setup' will always generate a new migration, even if you've
68
+ already run it before. this allows easy version upgrades.
69
+
70
+ - a few command would blow up on windows because they weren't prefixed with
71
+ 'ruby'. gotta love the lack of #shebang line on windoze...
72
+
73
+ - ./script/bj is searched first before system path env var
74
+
75
+ - a default PATH is provided for whacky systems without one
76
+
77
+ - database.yml is filtered through ERB ala rails
78
+
79
+ 0.0.2:
80
+ - path bug fixes
81
+
82
+ 0.0.1:
83
+ - initial release
data/LICENSE ADDED
@@ -0,0 +1 @@
1
+ same as ruby's
data/README ADDED
@@ -0,0 +1,318 @@
1
+ NAME
2
+ bj
3
+
4
+ SYNOPSIS
5
+ bj (migration_code|generate_migration|migrate|setup|plugin|run|submit|list|set|config|pid) [options]+
6
+
7
+ DESCRIPTION
8
+ ________________________________
9
+ Overview
10
+ --------------------------------
11
+
12
+ Backgroundjob (Bj) is a brain dead simple, zero admin, background priority
13
+ queue for Rails. Bj is robust, platform independent (including winblows),
14
+ and supports internal or external manangement of the background runner
15
+ process.
16
+
17
+ Jobs can be submitted to the queue directly using the api or from the command
18
+ line using the ./script/bj:
19
+
20
+ api:
21
+ Bj.submit 'cat /etc/password'
22
+
23
+ command line:
24
+ bj submit cat /etc/password
25
+
26
+ Bj's priority queue lives in the database and is therefore durable - your
27
+ jobs will live across an app crash or machine reboot. The job management is
28
+ comprehensive - capturing stdout, stderr, exit_status, and temporal
29
+ statistics about each job:
30
+
31
+ jobs =
32
+ Bj.submit command_or_array_of_commands, :priority => 42
33
+
34
+ ...
35
+
36
+ jobs.each do |job|
37
+ if job.finished?
38
+ p job.stdout
39
+ p job.stderr
40
+ p job.exit_status
41
+ p job.started_at
42
+ p job.finished_at
43
+ end
44
+ end
45
+
46
+ In addition the background runner process logs all commands run and their
47
+ exit_status to a log named using the following convention:
48
+
49
+ rails_root/log/bj.#{ HOSTNAME }.#{ RAILS_ENV }.log
50
+
51
+ Bj allows you to submit jobs to multiple databases; for instance, if your
52
+ application is running in development mode you may do:
53
+
54
+ Bj.in :production do
55
+ Bj.submit 'my_job.exe'
56
+ end
57
+
58
+ Bj manages the ever growing list of jobs ran by automatically archiving them
59
+ into another table (by default jobs > 24 hrs old are archived) to prevent the
60
+ jobs table from becoming bloated and huge.
61
+
62
+ All Bj's tables are namespaced and accessible via the Bj module:
63
+
64
+ Bj.table.job.find(:all) # jobs table
65
+ Bj.table.job_archive.find(:all) # archived jobs
66
+ Bj.table.config.find(:all) # configuration and runner state
67
+
68
+ Bj always arranges for submitted jobs to run with a current working
69
+ directory of RAILS_ROOT and with the correct RAILS_ENV setting. For
70
+ example, if you submit a job in production it will have ENV['RAILS_ENV'] ==
71
+ 'production' when the job is ran.
72
+
73
+ When Bj manages the background runner it will never outlive the rails
74
+ application - it is started and stopped on demand in parallel with the rails
75
+ app parent process. This is also true for ./script/console - Bj will
76
+ automatically fire off the background runner to process jobs submitted using
77
+ the console iff needed.
78
+
79
+ Bj starts *one process per server*. For instance, if you are running 3
80
+ mongrels via mongrel cluster Bj will automatically fire up *one background
81
+ process* per mongrel. This helps you scale background processes in a
82
+ relatively POLS fashion, but note that the number of background runners does
83
+ not *really* determine throughput - that is determined primarily by the
84
+ nature of the jobs themselves and how much work they perform per process,
85
+ though having more background processes can also help.
86
+
87
+
88
+ ________________________________
89
+ Architecture
90
+ --------------------------------
91
+
92
+ If one ignores platform specific details the design of Bj is quite simple: the
93
+ main Rails application submits jobs to table, stored in the database. The act
94
+ of submitting triggers exactly one of two things to occur:
95
+
96
+ 1) a new long running background runner to be started
97
+
98
+ 2) an existing background runner to be signaled
99
+
100
+ The background runner refuses to run two copies of itself for a given
101
+ hostname/rails_env combination. For example you may only have one background
102
+ runner processing jobs on localhost in development mode.
103
+
104
+ The background runner, under normal circumstances, is managed by Bj itself -
105
+ you need do nothing to start, monitor, or stop it - it just works. However,
106
+ some people will prefer manage their own background process, see 'External
107
+ Runner' section below for more on this.
108
+
109
+ The runner simply processes each job in a highest priority oldest-in fashion,
110
+ capturing stdout, stderr, exit_status, etc. and storing the information back
111
+ into the database while logging it's actions. When there are no jobs to run
112
+ the runner goes to sleep for 42 seconds; however this sleep is interuptable,
113
+ such as when the runner is signaled that a new job has been submitted so,
114
+ under normal circumstances there will be zero lag between job submission and
115
+ job running for an empty queue.
116
+
117
+
118
+ ________________________________
119
+ External Runner / Clustering
120
+ --------------------------------
121
+
122
+ For the paranoid control freaks out there (myself included) it is quite
123
+ possible to manage and monitor the runner process manually. This can be
124
+ desirable in production setups where monitoring software may kill leaking
125
+ rails apps periodically or in any case where you want to montior and control
126
+ the background process directly.
127
+
128
+ Recalling that Bj will only allow one copy of itself to process jobs per
129
+ hostname/rails_env pair we can simply do something like this in cron
130
+
131
+ cmd = bj run --forever \
132
+ --rails_env=development \
133
+ --rails_root=/Users/ahoward/rails_root
134
+
135
+ */15 * * * * $cmd
136
+
137
+ this will simply attempt the start the background runner every 15 minutes if,
138
+ and only if, it's not *already* running.
139
+
140
+ In addtion to this you'll want to tell Bj not to manage the runner itself
141
+ using
142
+
143
+ Bj.config["production.no_tickle"] = true
144
+
145
+ For instance in ./config/initializer/bj.rb or ./config/environment.rb.
146
+
147
+ Note that, for clusting setups, it's as simple as adding a crontab and
148
+ config entry like this for each host you app is running on. Because Bj
149
+ throttles background runners per hostname this will allow one runner per
150
+ hostname - making it quite simple to cluster three nodes behind a besieged
151
+ rails application.
152
+
153
+
154
+ ________________________________
155
+ Designing Jobs
156
+ --------------------------------
157
+
158
+ Bj runs it's jobs as command line applications. It ensures that all jobs run
159
+ in RAILS_ROOT so it's quite natural to apply a pattern such as
160
+
161
+ mkdir ./jobs
162
+ edit ./jobs/background_job_to_run
163
+
164
+ ...
165
+
166
+ Bj.submit "./jobs/background_job_to_run"
167
+
168
+ If you need to run you jobs under an entire rails environment you'll need to
169
+ do this:
170
+
171
+ Bj.submit "./script/runner ./jobs/background_job_to_run"
172
+
173
+ Obviously "./script/runner" loads the rails environment for you. It's worth
174
+ noting that this happens for each job and that this is by design: the reason
175
+ is that most rails applications leak memory like a sieve so, if one were to
176
+ spawn a long running process that used the application code base you'd have a
177
+ lovely doubling of memory usage on you app servers. Although loading the
178
+ rails environment for each background job requires a little time, a little
179
+ cpu, and a lot less memory. A future version of Bj will provide a way to load
180
+ the rails environment once and to process background jobs in this environment,
181
+ but anyone wanting to use this in production will be required to duct tape
182
+ their entire chest and have a team of oxen rip off the tape without screaming
183
+ to prove steelyness of spirit and profound understanding of the other side.
184
+
185
+ Don't forget that you can submit jobs with command line arguments:
186
+
187
+ Bj.submit "./jobs/a.rb 1 foobar --force"
188
+
189
+ and that you can do powerful things by passing stdin to a job that powers
190
+ through a list of work. For instance, assume a "./jobs/bulkmail" job
191
+ resembling
192
+
193
+ STDIN.each do |line|
194
+ address = line.strip
195
+ mail_message_to address
196
+ end
197
+
198
+ then you could
199
+
200
+ stdin = [
201
+ "foo@bar.com",
202
+ "bar@foo.com",
203
+ "ara.t.howard@codeforpeople.com",
204
+ ]
205
+
206
+ Bj.submit "./script/runner ./jobs/bulkmail", :stdin => stdin
207
+
208
+ and all those emails would be sent in the background.
209
+
210
+ Bj's power is putting jobs in the background in a simple and robust fashion.
211
+ It's your task to build intelligent jobs that leverage batch processing, and
212
+ other, possibilities. The upshot of building tasks this way is that they are
213
+ quite easy to test before submitting them from inside your application.
214
+
215
+
216
+ ________________________________
217
+ Install
218
+ --------------------------------
219
+
220
+ Bj can be installed two ways: as a plugin or via rubygems
221
+
222
+ plugin:
223
+ 1) ./script/plugin install http://codeforpeople.rubyforge.org/svn/rails/plugins/bj
224
+ 2) ./script/bj setup
225
+
226
+ gem:
227
+ 1) $sudo gem install bj
228
+ 2) add "require 'bj'" to config/environment.rb
229
+ 3) bj setup
230
+
231
+ ________________________________
232
+ Api
233
+ --------------------------------
234
+
235
+ submit jobs for background processing. 'jobs' can be a string or array of
236
+ strings. options are applied to each job in the 'jobs', and the list of
237
+ submitted jobs is always returned. options (string or symbol) can be
238
+
239
+ :rails_env => production|development|key_in_database_yml
240
+ when given this keyword causes bj to submit jobs to the
241
+ specified database. default is RAILS_ENV.
242
+
243
+ :priority => any number, including negative ones. default is zero.
244
+
245
+ :tag => a tag added to the job. simply makes searching easier.
246
+
247
+ :env => a hash specifying any additional environment vars the background
248
+ process should have.
249
+
250
+ :stdin => any stdin the background process should have. must respond_to
251
+ to_s
252
+
253
+ eg:
254
+
255
+ jobs = Bj.submit 'echo foobar', :tag => 'simple job'
256
+
257
+ jobs = Bj.submit '/bin/cat', :stdin => 'in the hat', :priority => 42
258
+
259
+ jobs = Bj.submit './script/runner ./scripts/a.rb', :rails_env => 'production'
260
+
261
+ jobs = Bj.submit './script/runner /dev/stdin',
262
+ :stdin => 'p RAILS_ENV',
263
+ :tag => 'dynamic ruby code'
264
+
265
+ jobs Bj.submit array_of_commands, :priority => 451
266
+
267
+ when jobs are run, they are run in RAILS_ROOT. various attributes are
268
+ available *only* once the job has finished. you can check whether or not a
269
+ job is finished by using the #finished method, which simple does a reload and
270
+ checks to see if the exit_status is non-nil.
271
+
272
+ eg:
273
+
274
+ jobs = Bj.submit list_of_jobs, :tag => 'important'
275
+ ...
276
+
277
+ jobs.each do |job|
278
+ if job.finished?
279
+ p job.exit_status
280
+ p job.stdout
281
+ p job.stderr
282
+ end
283
+ end
284
+
285
+ See lib/bj/api.rb for more details.
286
+
287
+ ________________________________
288
+ Sponsors
289
+ --------------------------------
290
+ http://quintess.com/
291
+ http://www.engineyard.com/
292
+ http://igicom.com/
293
+ http://eparklabs.com/
294
+
295
+ http://your_company.com/ <<-- (targeted marketing aimed at *you*)
296
+
297
+ ________________________________
298
+ Version
299
+ --------------------------------
300
+ 1.0.1
301
+
302
+ PARAMETERS
303
+ --rails_root=rails_root, -R (0 ~> rails_root=)
304
+ the rails_root will be guessed unless you set this
305
+ --rails_env=rails_env, -E (0 ~> rails_env=development)
306
+ set the rails_env
307
+ --log=log, -l (0 ~> log=STDERR)
308
+ set the logfile
309
+ --help, -h
310
+
311
+ AUTHOR
312
+ ara.t.howard@gmail.com
313
+
314
+ URIS
315
+ http://codeforpeople.com/lib/ruby/
316
+ http://rubyforge.org/projects/codeforpeople/
317
+ http://codeforpeople.rubyforge.org/svn/rails/plugins/
318
+
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "SciMed-bj"
8
+ gem.summary = %Q{Minor fork of ahoward/bj}
9
+ gem.description = %Q{Forked ahoward/bj because the way the bin/bj before_run method interacts with Main's logger= instance menthod breaks in Ruby 1.8.7. Forked again to add missing 'require logger'}
10
+ gem.email = ["josh.warchol@vibes.com", 'jk@jkraemer.net']
11
+ gem.homepage = "http://github.com/jkraemer/bj"
12
+ gem.authors = ["Ara T. Howard", "Joshua Warchol", "Jens Kraemer"]
13
+ gem.add_dependency 'main', '>= 2.6.0'
14
+ gem.add_dependency 'systemu', '>= 1.2.0'
15
+ gem.add_dependency 'orderedhash', '>= 0.0.3'
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Bj (or a dependency) not available."
20
+ puts $!
21
+ end
22
+
@@ -0,0 +1,77 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{SciMed-bj}
8
+ s.version = "1.2.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ara T. Howard", "Joshua Warchol", "Jens Kraemer"]
12
+ s.date = %q{2011-08-23}
13
+ s.default_executable = %q{bj}
14
+ s.description = %q{Forked ahoward/bj because the way the bin/bj before_run method interacts with Main's logger= instance menthod breaks in Ruby 1.8.7. Forked again to add missing 'require logger'}
15
+ s.email = ["josh.warchol@vibes.com", "jk@jkraemer.net"]
16
+ s.executables = ["bj"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README",
20
+ "TODO"
21
+ ]
22
+ s.files = [
23
+ "HISTORY",
24
+ "LICENSE",
25
+ "README",
26
+ "Rakefile",
27
+ "SciMed-bj.gemspec",
28
+ "TODO",
29
+ "VERSION",
30
+ "bin/bj",
31
+ "init.rb",
32
+ "install.rb",
33
+ "lib/bj.rb",
34
+ "lib/bj/api.rb",
35
+ "lib/bj/bj.rb",
36
+ "lib/bj/errors.rb",
37
+ "lib/bj/joblist.rb",
38
+ "lib/bj/logger.rb",
39
+ "lib/bj/runner.rb",
40
+ "lib/bj/stdext.rb",
41
+ "lib/bj/table.rb",
42
+ "lib/bj/util.rb",
43
+ "plugin/HISTORY",
44
+ "plugin/README",
45
+ "plugin/Rakefile",
46
+ "plugin/init.rb",
47
+ "plugin/install.rb",
48
+ "plugin/script/bj",
49
+ "plugin/tasks/bj_tasks.rake",
50
+ "plugin/test/bj_test.rb",
51
+ "plugin/uninstall.rb",
52
+ "todo.yml"
53
+ ]
54
+ s.homepage = %q{http://github.com/jkraemer/bj}
55
+ s.require_paths = ["lib"]
56
+ s.rubygems_version = %q{1.4.2}
57
+ s.summary = %q{Minor fork of ahoward/bj}
58
+
59
+ if s.respond_to? :specification_version then
60
+ s.specification_version = 3
61
+
62
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
63
+ s.add_runtime_dependency(%q<main>, [">= 2.6.0"])
64
+ s.add_runtime_dependency(%q<systemu>, [">= 1.2.0"])
65
+ s.add_runtime_dependency(%q<orderedhash>, [">= 0.0.3"])
66
+ else
67
+ s.add_dependency(%q<main>, [">= 2.6.0"])
68
+ s.add_dependency(%q<systemu>, [">= 1.2.0"])
69
+ s.add_dependency(%q<orderedhash>, [">= 0.0.3"])
70
+ end
71
+ else
72
+ s.add_dependency(%q<main>, [">= 2.6.0"])
73
+ s.add_dependency(%q<systemu>, [">= 1.2.0"])
74
+ s.add_dependency(%q<orderedhash>, [">= 0.0.3"])
75
+ end
76
+ end
77
+