asset_ram 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 201c96bf0cd23662ec2b7b3f68ebc17935a38a2ade97c1d3c025e7efe1492f28
4
- data.tar.gz: 0640c99917e1d5bd6d064f34ecffee34d34e9459ae529c787c89ea02c1b1d449
3
+ metadata.gz: 05464224fe91ef9aeb8784b87a9331802f9f1625f13e75969f672dccd4548dcd
4
+ data.tar.gz: 1c5c4845548975b31204a71da7cdd8410b69c4806b191adc8c2047669a6cfd56
5
5
  SHA512:
6
- metadata.gz: 6e259782f7f9b0bbc2129cf453b43d7e3889f35fe0ca6f5b98ed737977ccd21a46f773fdfaf8abdab62f67b2218557ee211038c22aca08454e9b378fcf4e0482
7
- data.tar.gz: a7a2c855608200a56146ab8aed9f8c0994e01a452c41b72e45073bfa0bcd9b955bb2f6d32e748aa41632c58d61c29ee6c6765e5cc9826ea6c09c750421023aaf
6
+ metadata.gz: 553e142c91b2dc4a5d4f1ff379524c65be3400d17498bba2cd549f81d4970077f037e4d329a3ec1d327e67e18d39f61b0ae946bf3e7e053c4f15ecef1c38f384
7
+ data.tar.gz: cd10e4447bdbaeeb29d795f7862b33dea15320a5fc240a165850785be2d53da04da1d96979eb628edfecb01bd5e692f26c6dacc10230083a0e1401a83f4970a4
data/README.md CHANGED
@@ -1,8 +1,102 @@
1
1
  # AssetRam
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/asset_ram`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ In a nutshell, for [a typical dynamic page](https://texas.public.law/statutes/tex._fam._code_section_1.001) in my Rails app, I get:
4
+
5
+ * 71% reduction in execution time
6
+ * 83% reduction in allocations
7
+
8
+ My app has been amazingly efficient since using these: memory usage stays flat at just 50% usage (512MB) for 4 Puma workers. It's very quick, with production response times averaging 37ms on a Heroku 1GB Standard-2x Dyno.
9
+
10
+
11
+ ## Example stats for [the page](https://texas.public.law/statutes/tex._fam._code_section_1.001)
12
+
13
+ Without AssetRam:
14
+
15
+ ```
16
+ Completed 200 OK in 38ms (Views: 34.2ms | ActiveRecord: 0.9ms | Allocations: 30332)
17
+ ```
18
+
19
+ With AssetRam:
20
+
21
+ ```
22
+ Completed 200 OK in 11ms (Views: 5.1ms | ActiveRecord: 1.3ms | Allocations: 5208)
23
+ ```
24
+
25
+
26
+ ## Usage
27
+
28
+ Wrap every asset helper call with `#cache`, like this:
29
+
30
+ ### Before
31
+
32
+ ```ruby
33
+ <%= favicon_link_tag('favicon/favicon.ico', rel: 'icon') %>
34
+ ```
35
+
36
+ ### After
37
+
38
+ ```ruby
39
+ <%= AssetRam::Helper.cache { favicon_link_tag('favicon/favicon.ico', rel: 'icon') } %>
40
+ ```
41
+
42
+ After booting up, messages like these will appear _once_ in the log. They show the
43
+ full cache key.
44
+
45
+ ```
46
+ Caching ["/Users/robb/src/PublicLaw/public-law-website/app/views/application/_html_head.haml", 16, "texas"]
47
+ Caching ["/Users/robb/src/PublicLaw/public-law-website/app/views/application/_favicon.haml", 8]
48
+ Caching ["/Users/robb/src/PublicLaw/public-law-website/app/views/application/_favicon.haml", 11]
49
+ ```
50
+
51
+ I use it in my footer for social icons as well: (HAML syntax)
52
+
53
+ ```ruby
54
+ = link_to asset.cache { image_tag("social/instagram-logo.svg", alt: 'Instagram', loading: 'lazy', decoding: 'async') }, "https://www.instagram.com/law.is.code/"
55
+ = link_to asset.cache { image_tag("social/facebook-logo-button.svg", alt: 'Facebook', loading: 'lazy', decoding: 'async') }, "https://www.facebook.com/PublicDotLaw"
56
+ = link_to asset.cache { image_tag("social/twitter-logo-button.svg", alt: 'Twitter', loading: 'lazy', decoding: 'async') }, "https://twitter.com/law_is_code"
57
+ = link_to asset.cache { image_tag("social/github-logo.svg", alt: 'Our GitHub Page', loading: 'lazy', decoding: 'async') }, "https://www.github.com/public-law/"
58
+ ```
59
+
60
+
61
+
62
+
63
+ ### In some cases, the cache key can't be inferred.
64
+
65
+ RamCache creates the cache key automatically using the view source filename and line number.
66
+ This works for most uses.
67
+
68
+ Some of my app's views are an exception, however. It's multi-tenant and the views serve content
69
+ for several sub-domains. And so the call to `#cache` allows extra key info to be passed.
70
+ In my HTML HEAD view, I have a `site` variable for choosing the CSS file for the domain:
71
+
72
+ ```ruby
73
+ <%= AssetRam::Helper.cache(key: site) { stylesheet_link_tag("themes/#{site}", media: nil) } %>
74
+ ```
75
+
76
+ ## Background: I was looking for ways to reduce allocations in my Rails app
77
+
78
+ In an effort to help my app run in a small 512MB virtual server, I looked through every view
79
+ invocation in the logs. After I optimized a bunch of my code, I realized that the asset helpers
80
+ create a relatively large amount of objects. The code is pretty complex too implying some amount
81
+ of CPU overhead. Moreover, this work is done over **on every request**.
82
+
83
+ These asset fingerprints are potentially re-generated on every deploy. So they can't be stored in
84
+ the usual Rails cache. I realized that storing the computed paths in a simple hash (in RAM only)
85
+ would be fast and never return stale data: The RAM cache goes away on a deploy/restart, which is
86
+ when asset fingerprints could change.
87
+
88
+ And so one-by-one I started storing the computed asset paths in a hash, and saw pretty dramatic results.
89
+
90
+ ## How it works: Block-based code executed in the view's context and inferred cache keys
91
+
92
+ Rails has some magic around when the asset helpers are able to create the fingerprint path. I found
93
+ that the caching needs to be done within the context of a view. This is why the lib's API looks
94
+ the way it does.
95
+
96
+ To make it as easy as possible to use, the lib finds the view's source filename and the line number of
97
+ the code being cached. This has been working well and in production for four months in a large Rails app.
98
+
4
99
 
5
- TODO: Delete this and the text above, and describe your gem
6
100
 
7
101
  ## Installation
8
102
 
@@ -20,9 +114,6 @@ Or install it yourself as:
20
114
 
21
115
  $ gem install asset_ram
22
116
 
23
- ## Usage
24
-
25
- TODO: Write usage instructions here
26
117
 
27
118
  ## Development
28
119
 
@@ -30,10 +121,6 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
30
121
 
31
122
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
123
 
33
- ## Contributing
34
-
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/asset_ram.
36
-
37
124
  ## License
38
125
 
39
126
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AssetRam
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/asset_ram.rb CHANGED
@@ -5,7 +5,7 @@ require_relative "asset_ram/version"
5
5
  #
6
6
  # Use in views to cache the asset path computation.
7
7
  #
8
- # For example, in an ERB file:
8
+ # For example, in a HAML file:
9
9
  #
10
10
  # = AssetRam::Helper.cache { favicon_link_tag('favicon/favicon.ico', rel: 'icon') }
11
11
  #
@@ -17,6 +17,9 @@ require_relative "asset_ram/version"
17
17
  #
18
18
  # = AssetRam::Helper.cache(key: site) { stylesheet_link_tag("themes/#{site}", media: nil) }
19
19
  #
20
+ # To test and compare if this lib actually improves performance,
21
+ # set the ASSET_RAM_DISABLE env var and it will transparently never cache.
22
+ #
20
23
  #
21
24
  module AssetRam
22
25
  class Error < StandardError; end
@@ -25,16 +28,10 @@ module AssetRam
25
28
  # Our own asset helper which memoizes Rails' asset helper calls.
26
29
  class Helper
27
30
 
28
- ##
29
- # For testing the gains from caching with this library.
30
- # Set to true to disable caching.
31
- NO_CACHE = false
32
-
33
31
  @@_cache = {}
34
32
 
35
-
36
33
  def self.cache(key: '', &blk)
37
- return yield if NO_CACHE
34
+ return yield if ENV['ASSET_RAM_DISABLE']
38
35
 
39
36
  cache_key = blk.source_location
40
37
  cache_key << key if key.present?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asset_ram
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robb Shecter