methodmissing-scrooge 1.0.1 → 1.0.2

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.
Files changed (35) hide show
  1. data/README.textile +227 -22
  2. data/VERSION.yml +1 -1
  3. data/assets/config/scrooge.yml.template +6 -0
  4. data/lib/scrooge/framework/base.rb +26 -15
  5. data/lib/scrooge/framework/rails.rb +28 -4
  6. data/lib/scrooge/middleware/tracker.rb +0 -1
  7. data/lib/scrooge/orm/active_record.rb +7 -3
  8. data/lib/scrooge/profile.rb +72 -73
  9. data/lib/scrooge/strategy/base.rb +74 -0
  10. data/lib/scrooge/strategy/controller.rb +29 -0
  11. data/lib/scrooge/strategy/scope.rb +14 -0
  12. data/lib/scrooge/strategy/stage.rb +77 -0
  13. data/lib/scrooge/strategy/track.rb +19 -0
  14. data/lib/scrooge/strategy/track_then_scope.rb +41 -0
  15. data/lib/scrooge/tracker/app.rb +63 -3
  16. data/lib/scrooge/tracker/base.rb +10 -0
  17. data/lib/scrooge/tracker/model.rb +7 -0
  18. data/lib/scrooge/tracker/resource.rb +17 -2
  19. data/lib/scrooge.rb +2 -1
  20. data/rails/init.rb +1 -1
  21. data/spec/fixtures/config/scrooge.yml +5 -1
  22. data/spec/units/scrooge/framework/base_spec.rb +9 -3
  23. data/spec/units/scrooge/profile_spec.rb +13 -15
  24. data/spec/units/scrooge/strategy/base_spec.rb +62 -0
  25. data/spec/units/scrooge/strategy/controller_spec.rb +26 -0
  26. data/spec/units/scrooge/strategy/scope_spec.rb +18 -0
  27. data/spec/units/scrooge/strategy/stage_spec.rb +35 -0
  28. data/spec/units/scrooge/strategy/track_spec.rb +19 -0
  29. data/spec/units/scrooge/strategy/track_then_scope_spec.rb +22 -0
  30. data/spec/units/scrooge/tracker/app_spec.rb +5 -1
  31. data/spec/units/scrooge/tracker/base_spec.rb +8 -0
  32. data/spec/units/scrooge/tracker/model_spec.rb +14 -1
  33. data/spec/units/scrooge/tracker/resource_spec.rb +21 -0
  34. data/tasks/scrooge.rake +1 -1
  35. metadata +16 -2
data/README.textile CHANGED
@@ -14,11 +14,15 @@ h2. Why bother ?
14
14
 
15
15
  h2. Suggested Use
16
16
 
17
- Scrooge *requires* a comprehensive existing functional or integration test suite for best results.If test coverage is flaky or non-existent, then a) you shouldn't worry about performance tuning and b) shouldn't be reading this - go spec.
17
+ There's 3 basic modes of operation :
18
18
 
19
- There's 2 basic modes of operation, a tracking or a scope phase.
19
+ * Track : Track attribute access to dump a representative scope profile.
20
20
 
21
- h4. Resources
21
+ * Scope : Scope the process and related resources to a previously persisted scope profile.
22
+
23
+ * Track then scope : A multi-stage strategy that tracks attribute access for
24
+
25
+ h2. Resources
22
26
 
23
27
  A resource is :
24
28
 
@@ -28,24 +32,23 @@ A resource is :
28
32
 
29
33
  All Model to attribute mappings is tracked on a per Resource basis.Multiple Models per Resource is supported.
30
34
 
35
+ h2. Strategies
36
+
31
37
  h4. Tracking
32
38
 
33
- In tracking mode, which is the default when no scope is given and Scrooge is enabled, Scrooge installs filters ( either through Rack middleware or framework specific hooks ) that track attribute access on a per Resource basis.
39
+ In tracking mode Scrooge installs filters ( either through Rack middleware or framework specific hooks ) that track attribute access on a per Resource basis.
34
40
 
35
41
  A Kernel#at_exit callback dumps and timestamps this profile ( or scope ) to eg. *framework_configuration_directory/config/scopes/1234147851/scope.yml*
36
42
 
37
- This typically happens during functional or integration testing.
43
+ This typically works well with functional or integration testing and can yield a substantial birds eye view of attribute
44
+ use.The accuracy is directly proportional to test coverage and the quality of the test suite.
38
45
 
39
- The test log may look like :
46
+ Example log output :
40
47
 
41
48
  <pre>
42
49
  <code>
43
50
  Processing HotelsController#index (for 0.0.0.0 at 2009-02-09 02:55:55) [GET]
44
51
  Parameters: {"action"=>"index", "controller"=>"hotels"}
45
- [Scrooge] Track with resource #< :/ ()
46
- [Scrooge] Track for Resource #<GET :hotels/index (*/*)
47
- - #<Hotel :from_price, :narrative, :star_rating, :latitude, :created_at, :hotel_name, :updated_at, :important_notes, :id, :apt, :location_id, :nearest_tube, :longitude, :telephone, :nearest_rail, :location_name, :distance>
48
- - #<Image :thumbnail_width, :created_at, :title, :updated_at, :url, :thumbnail_height, :height, :thumbnail_url, :has_thumbnail, :hotel_id, :width>
49
52
  Hotel Load (0.3ms) SELECT * FROM `hotels` LIMIT 0, 15
50
53
  Rendering template within layouts/application
51
54
  Rendering hotels/index
@@ -154,20 +157,18 @@ An example scope / profile, saved to disk :
154
157
  </code>
155
158
  </pre>
156
159
 
157
- h4. Scoping
160
+ h4. Scope
158
161
 
159
162
  A previously persisted scope / profile can be restored from disk and injected to the applicable Resources.Database content retrieved will match that of the given scope timestamp.
160
163
 
161
- This is typically pushed to production and adjusted for each major release or deployment.
164
+ This is typically pushed to production where a hybrid ( track then scope strategy) mode of operation is frowned upon and adjusted for each major release or deployment.
162
165
 
163
- Log output may look like :
166
+ Example log output :
164
167
 
165
168
  <pre>
166
169
  <code>
167
170
  Processing HotelsController#index (for 0.0.0.0 at 2009-02-09 02:59:41) [GET]
168
171
  Parameters: {"action"=>"index", "controller"=>"hotels"}
169
- [Scrooge] Scope for Model #<Image :created_at, :thumbnail_width, :title, :updated_at, :url, :id, :thumbnail_height, :height, :thumbnail_url, :has_thumbnail, :width, :hotel_id>
170
- [Scrooge] Scope for Model #<Hotel :narrative, :from_price, :created_at, :latitude, :star_rating, :hotel_name, :updated_at, :important_notes, :apt, :id, :nearest_tube, :location_id, :nearest_rail, :telephone, :longitude, :distance, :location_name>
171
172
  Hotel Load (0.4ms) SELECT hotels.narrative, hotels.from_price, hotels.created_at, hotels.latitude, hotels.star_rating, hotels.hotel_name, hotels.updated_at, hotels.important_notes, hotels.apt, hotels.id, hotels.nearest_tube, hotels.location_id, hotels.nearest_rail, hotels.telephone, hotels.longitude, hotels.distance, hotels.location_name FROM `hotels` LIMIT 0, 15
172
173
  Rendering template within layouts/application
173
174
  Rendering hotels/index
@@ -184,6 +185,164 @@ Log output may look like :
184
185
  </code>
185
186
  </pre>
186
187
 
188
+ h4. Track then scope
189
+
190
+ Multi-stage and self configuring strategy that tracks attribute access for a given warmup period, synchronize the results across n-1 processes, aggregate the results to be representative of the whole cluster ( or seamless fallback to a single process ), remove the tracking filters and install functionality that scopes database access to that of the tracking phase.
191
+
192
+ Recommended for production use.
193
+
194
+ Example log output :
195
+
196
+ <pre>
197
+ <code>
198
+ Processing HotelsController#index (for 127.0.0.1 at 2009-02-16 00:00:58) [GET]
199
+ Parameters: {"action"=>"index", "controller"=>"hotels"}
200
+ Hotel Load (0.5ms) SELECT * FROM `hotels` LIMIT 0, 15
201
+ Hotel Columns (7.7ms) SHOW FIELDS FROM `hotels`
202
+ SQL (3.9ms) SELECT count(*) AS count_all FROM `hotels`
203
+ Rendering template within layouts/application
204
+ Rendering hotels/index
205
+ Image Load (0.5ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11381) LIMIT 1
206
+ Image Columns (3.6ms) SHOW FIELDS FROM `images`
207
+ Rendered hotels/_hotel (200.2ms)
208
+ Image Load (0.4ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11382) LIMIT 1
209
+ Rendered hotels/_hotel (2.4ms)
210
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11697) LIMIT 1
211
+ Rendered hotels/_hotel (1.8ms)
212
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12693) LIMIT 1
213
+ Rendered hotels/_hotel (1.7ms)
214
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12738) LIMIT 1
215
+ Rendered hotels/_hotel (1.6ms)
216
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12886) LIMIT 1
217
+ Rendered hotels/_hotel (1.9ms)
218
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13007) LIMIT 1
219
+ Rendered hotels/_hotel (1.8ms)
220
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13074) LIMIT 1
221
+ Rendered hotels/_hotel (1.5ms)
222
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13077) LIMIT 1
223
+ Rendered hotels/_hotel (1.6ms)
224
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13078) LIMIT 1
225
+ Rendered hotels/_hotel (1.8ms)
226
+ Image Load (0.3ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13079) LIMIT 1
227
+ Rendered hotels/_hotel (2.4ms)
228
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13080) LIMIT 1
229
+ Rendered hotels/_hotel (1.8ms)
230
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13082) LIMIT 1
231
+ Rendered hotels/_hotel (1.5ms)
232
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13085) LIMIT 1
233
+ Rendered hotels/_hotel (1.8ms)
234
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13105) LIMIT 1
235
+ Rendered hotels/_hotel (1.6ms)
236
+ Rendered shared/_header (0.4ms)
237
+ Rendered shared/_navigation (0.8ms)
238
+ Missing template hotels/_index_sidebar.erb in view path app/views
239
+ Rendered shared/_sidebar (0.4ms)
240
+ Rendered shared/_footer (0.3ms)
241
+ Completed in 270ms (View: 243, DB: 20) | 200 OK [http://localhost/hotels]
242
+ [Scrooge] Execute stage :synchronize ...
243
+ [Scrooge] Uninstalling tracking middleware ...
244
+ [Scrooge] Stop tracking ...
245
+ [Scrooge] Synchronize results with other processes ...
246
+ Cache write: 17619400_63223_756033
247
+ Cache read: scrooge_tracker_aggregation
248
+ Cache write: scrooge_tracker_aggregation
249
+ [Scrooge] Execute stage :aggregate ...
250
+ [Scrooge] Aggregate results from other processes ...
251
+
252
+
253
+ Processing HotelsController#index (for 127.0.0.1 at 2009-02-16 00:01:37) [GET]
254
+ Parameters: {"action"=>"index", "controller"=>"hotels"}
255
+ Hotel Load (0.5ms) SELECT * FROM `hotels` LIMIT 0, 15
256
+ SQL (0.2ms) SELECT count(*) AS count_all FROM `hotels`
257
+ Rendering template within layouts/application
258
+ Rendering hotels/index
259
+ Image Load (0.3ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11381) LIMIT 1
260
+ Rendered hotels/_hotel (2.0ms)
261
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11382) LIMIT 1
262
+ Rendered hotels/_hotel (1.8ms)
263
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11697) LIMIT 1
264
+ Rendered hotels/_hotel (1.7ms)
265
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12693) LIMIT 1
266
+ Rendered hotels/_hotel (1.6ms)
267
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12738) LIMIT 1
268
+ Rendered hotels/_hotel (1.5ms)
269
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12886) LIMIT 1
270
+ Rendered hotels/_hotel (1.8ms)
271
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13007) LIMIT 1
272
+ Rendered hotels/_hotel (1.8ms)
273
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13074) LIMIT 1
274
+ Rendered hotels/_hotel (1.4ms)
275
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13077) LIMIT 1
276
+ Rendered hotels/_hotel (1.6ms)
277
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13078) LIMIT 1
278
+ Rendered hotels/_hotel (1.6ms)
279
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13079) LIMIT 1
280
+ Rendered hotels/_hotel (1.8ms)
281
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13080) LIMIT 1
282
+ Rendered hotels/_hotel (1.7ms)
283
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13082) LIMIT 1
284
+ Rendered hotels/_hotel (1.5ms)
285
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13085) LIMIT 1
286
+ Rendered hotels/_hotel (1.7ms)
287
+ Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13105) LIMIT 1
288
+ Rendered hotels/_hotel (81.1ms)
289
+ Rendered shared/_header (0.1ms)
290
+ Rendered shared/_navigation (0.3ms)
291
+ Missing template hotels/_index_sidebar.erb in view path app/views
292
+ Rendered shared/_sidebar (0.1ms)
293
+ Rendered shared/_footer (0.1ms)
294
+ Completed in 113ms (View: 107, DB: 4) | 200 OK [http://localhost/hotels]
295
+ Cache read: scrooge_tracker_aggregation
296
+ Cache read: 17619400_63223_756033
297
+ [Scrooge] Execute stage :scope ...
298
+ [Scrooge] Scope ...
299
+
300
+
301
+ Processing HotelsController#index (for 127.0.0.1 at 2009-02-16 00:01:53) [GET]
302
+ Parameters: {"action"=>"index", "controller"=>"hotels"}
303
+ Hotel Load (0.7ms) SELECT hotels.narrative, hotels.from_price, hotels.created_at, hotels.latitude, hotels.star_rating, hotels.hotel_name, hotels.updated_at, hotels.important_notes, hotels.apt, hotels.id, hotels.nearest_tube, hotels.location_id, hotels.nearest_rail, hotels.telephone, hotels.longitude, hotels.distance, hotels.location_name FROM `hotels` LIMIT 0, 15
304
+ SQL (0.2ms) SELECT count(*) AS count_all FROM `hotels`
305
+ Rendering template within layouts/application
306
+ Rendering hotels/index
307
+ Image Load (0.3ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 11381) LIMIT 1
308
+ Rendered hotels/_hotel (2.0ms)
309
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 11382) LIMIT 1
310
+ Rendered hotels/_hotel (1.7ms)
311
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 11697) LIMIT 1
312
+ Rendered hotels/_hotel (1.7ms)
313
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 12693) LIMIT 1
314
+ Rendered hotels/_hotel (1.7ms)
315
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 12738) LIMIT 1
316
+ Rendered hotels/_hotel (1.5ms)
317
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 12886) LIMIT 1
318
+ Rendered hotels/_hotel (1.7ms)
319
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13007) LIMIT 1
320
+ Rendered hotels/_hotel (1.8ms)
321
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13074) LIMIT 1
322
+ Rendered hotels/_hotel (1.4ms)
323
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13077) LIMIT 1
324
+ Rendered hotels/_hotel (1.5ms)
325
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13078) LIMIT 1
326
+ Rendered hotels/_hotel (1.8ms)
327
+ Image Load (0.3ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13079) LIMIT 1
328
+ Rendered hotels/_hotel (1.9ms)
329
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13080) LIMIT 1
330
+ Rendered hotels/_hotel (1.7ms)
331
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13082) LIMIT 1
332
+ Rendered hotels/_hotel (1.5ms)
333
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13085) LIMIT 1
334
+ Rendered hotels/_hotel (1.7ms)
335
+ Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13105) LIMIT 1
336
+ Rendered hotels/_hotel (1.7ms)
337
+ Rendered shared/_header (0.1ms)
338
+ Rendered shared/_navigation (0.2ms)
339
+ Missing template hotels/_index_sidebar.erb in view path app/views
340
+ Rendered shared/_sidebar (0.0ms)
341
+ Rendered shared/_footer (0.0ms)
342
+ Completed in 34ms (View: 27, DB: 4) | 200 OK [http://localhost/hotels]
343
+ </code>
344
+ </pre>
345
+
187
346
  h2. Installation
188
347
 
189
348
  h4. As a Rails plugin ( Recommended )
@@ -203,24 +362,34 @@ h2. Configuration
203
362
 
204
363
  Scrooge installs ( see recommended installation above ) a configuration file with the following format within *framework_configuration_directory/scrooge.yml ( RAILS_ROOT/config/scrooge.yml for a Rails setup ) :
205
364
 
365
+ <pre>
366
+ <code>
206
367
  production:
207
368
  orm: :active_record
208
369
  storage: :memory
370
+ strategy: :track_then_scope
371
+ warmup: 600 # warmup / track for 10 minutes
209
372
  scope:
210
373
  on_missing_attribute: :reload # or :raise
211
- enabled: true
212
- development:
374
+ enabled: true
375
+ development:
213
376
  orm: :active_record
214
377
  storage: :memory
378
+ strategy: :track
379
+ warmup: 600 # warmup / track for 10 minutes
215
380
  scope:
216
381
  on_missing_attribute: :reload # or :raise
217
382
  enabled: true
218
383
  test:
219
384
  orm: :active_record
220
385
  storage: :memory
386
+ strategy: :track
387
+ warmup: 600 # warmup / track for 10 minutes
221
388
  scope:
222
389
  on_missing_attribute: :reload # or :raise
223
- enabled: true
390
+ enabled: true
391
+ </code>
392
+ </pre>
224
393
 
225
394
  h4. ORM
226
395
 
@@ -234,6 +403,14 @@ Tracking results can be persisted to a given backend or storage option.Ships wit
234
403
 
235
404
  storage: :memory
236
405
 
406
+ h4. Strategy
407
+
408
+ One of :track, :scope or :track_then_scope .Only the :track_then_scope strategy respects the :warmup configuration option.
409
+
410
+ h4. Warmup
411
+
412
+ The designated warmup period for the :track_then_scope strategy, given in seconds.Typically 600 to 3600.
413
+
237
414
  h4. Scope
238
415
 
239
416
  A scope is a reference to a timestamped Scrooge run where access to Model attributes is tracked on a per Resource basis.
@@ -254,9 +431,37 @@ Scrooge can be disabled with :
254
431
 
255
432
  enabled: false
256
433
 
257
- h2. Notes
434
+ h2. Rails specific rake tasks.
435
+
436
+ Ships with tasks to assist in inspecting results.
258
437
 
259
- This is an initial release, has not yet been battle tested in production and is pending Ruby 1.9.1 compatibility.
438
+ <pre>
439
+ <code>
440
+ methodmissing:superbreak_app lourens$ rake scrooge:list
441
+ (in /Users/lourens/projects/superbreak_app)
442
+ - 1234735663
443
+ - 1234735722
444
+ - 1234735744
445
+ - 1234735790
446
+ - 1234738880
447
+ methodmissing:superbreak_app lourens$ rake scope=1234735790 scrooge:inspect
448
+ (in /Users/lourens/projects/superbreak_app)
449
+ #<GET :hotels/show (*/*)
450
+ - #<Hotel :important_notes, :location_id>
451
+ - #<Address :line1, :created_at, :line2, :postcode, :updated_at, :country_id, :county, :location_id, :town, :hotel_id>
452
+
453
+ #<GET :countries/index (*/*)
454
+ - #<Country :name, :created_at, :code, :updated_at, :id, :location_id, :continent_id>
455
+
456
+ #<GET :locations/index (*/*)
457
+ - #<Location :name, :created_at, :code, :updated_at, :level, :id>
458
+
459
+ #<GET :hotels/index (*/*)
460
+ - #<Image :created_at, :thumbnail_width, :title, :updated_at, :url, :thumbnail_height, :height, :thumbnail_url, :has_thumbnail, :width, :hotel_id>
461
+ - #<Hotel :narrative, :from_price, :created_at, :latitude, :star_rating, :hotel_name, :updated_at, :important_notes, :apt, :id, :nearest_tube, :location_id, :nearest_rail, :telephone, :longitude, :distance, :location_name>
462
+ </code>
463
+ </pre>
464
+
465
+ h2. Notes
260
466
 
261
- Initially evaluated a centralized tracker concept for multi-server environments with minimal configuration overhead
262
- and on the fly scope injection after a given warmup threshold but found that to be overkill for a first release.
467
+ This is an initial release, has not yet been battle tested in production and is pending Ruby 1.9.1 compatibility.
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 1
2
+ :patch: 2
3
3
  :major: 1
4
4
  :minor: 0
@@ -1,18 +1,24 @@
1
1
  production:
2
2
  orm: :active_record
3
3
  storage: :memory
4
+ strategy: :track_then_scope
5
+ warmup: 600 # warmup / track for 10 minutes
4
6
  scope:
5
7
  on_missing_attribute: :reload # or :raise
6
8
  enabled: true
7
9
  development:
8
10
  orm: :active_record
9
11
  storage: :memory
12
+ strategy: :track
13
+ warmup: 600 # warmup / track for 10 minutes
10
14
  scope:
11
15
  on_missing_attribute: :reload # or :raise
12
16
  enabled: true
13
17
  test:
14
18
  orm: :active_record
15
19
  storage: :memory
20
+ strategy: :track
21
+ warmup: 600 # warmup / track for 10 minutes
16
22
  scope:
17
23
  on_missing_attribute: :reload # or :raise
18
24
  enabled: true
@@ -50,27 +50,27 @@ module Scrooge
50
50
  class InvalidScopeSignature < StandardError
51
51
  end
52
52
 
53
- class << self
54
-
55
- # Per framework signature lookup.
56
- #
57
- @@signatures = {}
58
- @@signatures[self.name] = Hash.new( [] )
59
-
60
- # Support none by default.
61
- #
62
- @@frameworks = []
53
+ # Per framework signature lookup.
54
+ #
55
+ @@signatures = Hash.new( [] )
56
+ @@signatures[self.name] = []
57
+
58
+ # Support none by default.
59
+ #
60
+ @@frameworks = []
61
+
62
+ class << self
63
63
 
64
64
  # Registers a framework signature.
65
65
  #
66
66
  def signature( &block )
67
- @@signatures[self.name] = signatures << block
67
+ @@signatures[self.name] << block
68
68
  end
69
69
 
70
70
  # All signatures for the current klass.
71
71
  #
72
72
  def signatures
73
- @@signatures[self.name] || []
73
+ @@signatures[self.name]
74
74
  end
75
75
 
76
76
  # All supported frameworks.
@@ -173,6 +173,12 @@ module Scrooge
173
173
  raise NotImplemented
174
174
  end
175
175
 
176
+ # Remove tracking middleware
177
+ #
178
+ def uninstall_tracking_middleware
179
+ raise NotImplemented
180
+ end
181
+
176
182
  # Register a code block to run when the host framework is fully initialized.
177
183
  #
178
184
  def initialized( &block )
@@ -202,7 +208,7 @@ module Scrooge
202
208
  # Return the scopes storage path for the current framework.
203
209
  #
204
210
  def scopes_path
205
- @profiles_path ||= File.join( config, 'scrooge', 'scopes' )
211
+ @scopes_path ||= File.join( config, 'scrooge', 'scopes' )
206
212
  end
207
213
 
208
214
  # Return the scopes storage path for a given scope and optional filename.
@@ -214,8 +220,9 @@ module Scrooge
214
220
 
215
221
  # Log a message to the logger.
216
222
  #
217
- def log( message )
223
+ def log( message, flush = false )
218
224
  logger.info "[Scrooge] #{message}"
225
+ flush_logger! if flush
219
226
  end
220
227
 
221
228
  # Persist the current tracker as scope or restore a previously persisted scope
@@ -251,7 +258,7 @@ module Scrooge
251
258
  GUARD.synchronize do
252
259
  scope = Time.now.to_i
253
260
  dump_scope!( scope )
254
- scope
261
+ scope.to_s
255
262
  end
256
263
  end
257
264
 
@@ -263,6 +270,10 @@ module Scrooge
263
270
 
264
271
  private
265
272
 
273
+ def flush_logger! #:nodoc:
274
+ logger.flush if logger.respond_to?(:flush)
275
+ end
276
+
266
277
  def restore_scope!( scope ) #:nodoc:
267
278
  tracker = Scrooge::Tracker::App.new
268
279
  tracker.marshal_load( scope_from_yaml( scope ) )
@@ -57,21 +57,31 @@ module Scrooge
57
57
  #
58
58
  def install_tracking_middleware
59
59
  GUARD.synchronize do
60
- ActionController::Dispatcher.to_prepare( :scrooge_install_tracking_middleware ) do
60
+ with_or_without_prepatation( :scrooge_install_tracking_middleware ) do
61
61
  ApplicationController.prepend_around_filter Scrooge::Middleware::Tracker
62
62
  end
63
63
  end
64
64
  end
65
65
 
66
+ # Remove all tracking filters
67
+ #
68
+ def uninstall_tracking_middleware
69
+ GUARD.synchronize do
70
+ # Handle dev. mode
71
+ ActionController::Dispatcher.prepare_dispatch_callback_chain.delete( :scrooge_install_tracking_middleware )
72
+ ApplicationController.skip_filter Scrooge::Middleware::Tracker
73
+ end
74
+ end
75
+
66
76
  # Install per Resource scoping middleware.
67
77
  #
68
78
  def install_scope_middleware( tracker )
69
79
  GUARD.synchronize do
70
- ActionController::Dispatcher.to_prepare( :scrooge_install_scope_middleware ) do
80
+ with_or_without_prepatation( :scrooge_install_scope_middleware ) do
71
81
  tracker.resources.each do |resource|
72
82
  install_scope_middleware_for_resource!( resource )
73
83
  end
74
- end
84
+ end
75
85
  end
76
86
  end
77
87
 
@@ -79,7 +89,7 @@ module Scrooge
79
89
  begin
80
90
  ::Rails.configuration.after_initialize( &block )
81
91
  rescue NameError
82
- # No cofig initialized - plugin installation etc.
92
+ # No config initialized - plugin installation etc.
83
93
  end
84
94
  end
85
95
 
@@ -89,6 +99,20 @@ module Scrooge
89
99
 
90
100
  private
91
101
 
102
+ def with_or_without_prepatation( callback_signature, &block ) #:nodoc:
103
+ if development?
104
+ ActionController::Dispatcher.to_prepare( callback_signature ) do
105
+ block.call
106
+ end
107
+ else
108
+ block.call
109
+ end
110
+ end
111
+
112
+ def development? #:nodoc:
113
+ environment == 'development'
114
+ end
115
+
92
116
  def install_scope_middleware_for_resource!( resource ) #:nodoc:
93
117
  resource.middleware.each do |resource_middleware|
94
118
  controller( resource ).prepend_around_filter resource_middleware, :only => resource.action
@@ -12,7 +12,6 @@ module Scrooge
12
12
  Scrooge::Base.profile.tracker.track( Thread.scrooge_resource ) do
13
13
  begin
14
14
  Scrooge::Base.profile.framework.resource( {}, controller.request )
15
- Scrooge::Base.profile.log "Track for Resource #{Thread.scrooge_resource.inspect}"
16
15
  block.call
17
16
  ensure
18
17
  Thread.reset_scrooge_resource!
@@ -28,7 +28,6 @@ module Scrooge
28
28
 
29
29
  def register_with_scrooge!( attr_name, caller ) #:nodoc:
30
30
  if ::Scrooge::Base.profile.orm.track?
31
- logger.info "[Scrooge] #{caller} #{attr_name.to_s}"
32
31
  Thread.scrooge_resource << [self.base_class, attr_name]
33
32
  end
34
33
  end
@@ -55,7 +54,6 @@ module Scrooge
55
54
 
56
55
  def register_with_scrooge!( attr_name, caller ) #:nodoc:
57
56
  if ::Scrooge::Base.profile.orm.track?
58
- logger.info "[Scrooge] #{caller} #{attr_name.to_s}"
59
57
  Thread.scrooge_resource << [self.class.base_class, attr_name]
60
58
  end
61
59
  end
@@ -105,7 +103,7 @@ module Scrooge
105
103
  #
106
104
  def scope_resource_to_model( resource, model )
107
105
  method_name = resource_scope_method( resource )
108
- klass = model.model.to_const!(false) if model.model.is_a?(String)
106
+ klass = klass_for_model( model )
109
107
  unless resource_scope_method?( resource, klass )
110
108
  klass.instance_eval(<<-EOS, __FILE__, __LINE__)
111
109
  def #{method_name}(&block)
@@ -138,6 +136,12 @@ module Scrooge
138
136
  model.primary_key
139
137
  end
140
138
 
139
+ private
140
+
141
+ def klass_for_model( model ) #:nodoc:
142
+ model.model.is_a?(String) ? model.model.to_const!(false) : model.model
143
+ end
144
+
141
145
  end
142
146
  end
143
147
  end