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 +4 -4
- data/README.md +96 -9
- data/lib/asset_ram/version.rb +1 -1
- data/lib/asset_ram.rb +5 -8
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05464224fe91ef9aeb8784b87a9331802f9f1625f13e75969f672dccd4548dcd
|
4
|
+
data.tar.gz: 1c5c4845548975b31204a71da7cdd8410b69c4806b191adc8c2047669a6cfd56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 553e142c91b2dc4a5d4f1ff379524c65be3400d17498bba2cd549f81d4970077f037e4d329a3ec1d327e67e18d39f61b0ae946bf3e7e053c4f15ecef1c38f384
|
7
|
+
data.tar.gz: cd10e4447bdbaeeb29d795f7862b33dea15320a5fc240a165850785be2d53da04da1d96979eb628edfecb01bd5e692f26c6dacc10230083a0e1401a83f4970a4
|
data/README.md
CHANGED
@@ -1,8 +1,102 @@
|
|
1
1
|
# AssetRam
|
2
2
|
|
3
|
-
|
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).
|
data/lib/asset_ram/version.rb
CHANGED
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
|
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
|
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?
|