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 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
+