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
data/HISTORY ADDED
@@ -0,0 +1,80 @@
1
+ 1.2.0
2
+ - fixes to docs
3
+ - added license
4
+ - factored out job running logic into job.run(), for testing
5
+ - added some specs. gasp.
6
+
7
+ 1.0.3
8
+ - env wasn't properly unpacked by runner, added YAML.load(job.env), thanks
9
+ Chris Wanstrath
10
+ - made operations that generate migrations, etc, verbose - they dump
11
+ stdout and stderr to console when running
12
+
13
+ 1.0.2:
14
+ - Bj now (should) auto detect the correct rake command on windows as
15
+ "rake.bat" not "rake". see Bj.which_rake and Bj.rake for impl.
16
+
17
+ 1.0.1:
18
+ - fixed name collision with 'record.attributes = hash' ar mass
19
+ assignment method (thx jon guymon)
20
+ - added new sponsor: http://igicom.com/
21
+
22
+ 0.0.5:
23
+ - use full path to ruby for plugin mode
24
+ - plugin correctly installs bin -->> script
25
+ - plugin install uses --force
26
+ - properly quote paths in windows (spaces)
27
+ - switch win signal to ABRT (was INT)
28
+ - background job regrestration now uses ppid to pin the subprocess to a
29
+ parent
30
+ - use ppid to detect parent death and exit in event loop
31
+ - don't use gem dependanices in plugin as they are broken when loading from
32
+ muliple gem repos
33
+ - added a small amount of drb magic that allows signals to work across
34
+ processes even on windows (see http://drawohara.com/post/22540307)
35
+
36
+ 0.0.4:
37
+ - basic functionality in windows
38
+ - several small bug fixes
39
+
40
+ 0.0.3:
41
+ - *many* small bug fixes
42
+
43
+ - plugin install should now pick up dependancies from plugin dir, last
44
+ release had LOAD_PATH/gem issues and was picking up globally installed
45
+ gems
46
+
47
+ - automatic management of the background processing can be turned off if you
48
+ want to manage your own processes
49
+
50
+ - all jobs are automatically restartable unless submitted with
51
+
52
+ :restartable => false
53
+
54
+ this means that, should a runner ever die, upon restart any jobs that were
55
+ mid-process will automatically be restarted
56
+
57
+ - signal based parent lifeline move out of thread and into even loop
58
+
59
+ - :lock => true added to a few AR finds to support true write serializable
60
+ transaction isolation when the db supports it
61
+
62
+ - all migrations now use :force => true and
63
+
64
+ - running 'bj setup' will always generate a new migration, even if you've
65
+ already run it before. this allows easy version upgrades.
66
+
67
+ - a few command would blow up on windows because they weren't prefixed with
68
+ 'ruby'. gotta love the lack of #shebang line on windoze...
69
+
70
+ - ./script/bj is searched first before system path env var
71
+
72
+ - a default PATH is provided for whacky systems without one
73
+
74
+ - database.yml is filtered through ERB ala rails
75
+
76
+ 0.0.2:
77
+ - path bug fixes
78
+
79
+ 0.0.1:
80
+ - 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,20 @@
1
+ task :foobar do
2
+ puts 42
3
+ end
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |spec|
8
+ spec.name = 'bj'
9
+ spec.summary = "Backgroundjob (Bj) is a brain dead simple, zero admin, background priority queue for Rails."
10
+ spec.description = "Backgroundjob (Bj) is a brain dead simple, zero admin, background priority queue for Rails."
11
+ spec.add_dependency 'main', '>= 2.6.0'
12
+ spec.add_dependency 'systemu', '>= 1.2.0'
13
+ spec.add_dependency 'orderedhash', '>= 0.0.3'
14
+ spec.author = "Ara T. Howard"
15
+ spec.email = "ara.t.howard@gmail.com"
16
+ spec.files.reject! { |fn| fn.include? ".git" }
17
+ end
18
+ rescue LoadError
19
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
20
+ end
data/TODO ADDED
@@ -0,0 +1,53 @@
1
+
2
+ - fix TZ bug
3
+
4
+ - fix doc bug regarding runners
5
+
6
+ - crontab option
7
+
8
+ - make tickle easier
9
+
10
+ - eval option
11
+
12
+ - flesh out the cli interface - it's a test only at this point
13
+
14
+ - commands need quoting, esp for windows, "c:\Documents And..." etc
15
+
16
+
17
+
18
+
19
+ - the whole gem_path thing is still fubar
20
+
21
+ - signals not operating properly on windows , non critical error tho...
22
+
23
+ - need to figure out how to cache connections for Bj.in(...)
24
+
25
+ - ttl will be added. maxing it out will cause auto-resubmission (Steve Midgley)
26
+
27
+ - is having the runner thread try forever to start the process the best thing?
28
+
29
+ - allow easy way to run ruby code. perhaps ./script/runner 'eval STDIN.read'
30
+ is good enough
31
+
32
+ - allow easy way to run ruby code that persists
33
+
34
+ - allow specification of runner on submit (--runner)
35
+
36
+ - allow specification of tags a runner will consume (--tag)
37
+
38
+ - test in windows
39
+
40
+ ================================================================================
41
+
42
+ X ./script/console submission hangs on windows
43
+ X default PATH setting
44
+ X install issues for dave? - gem_path...
45
+ X main only loaded for (bin|script)/bj
46
+ X make it possible to declare externally managed runners
47
+ X restartable will be added. true by default (Steve Midgley)
48
+ X do the lifeline inline with the loop
49
+ X need to address the serialzable writer issue (:lock => true ??)
50
+ X migrations use --force
51
+ X i forget to add "#{ Bj.ruby } ... " to the generate command
52
+ X ./script/bj must be found in path before c:/.....bin/bj
53
+ X make sure database.yml is loaded via YAML::load(ERB.new(File.read * "config/database.yml").result)