asset_ram 0.1.0 → 0.2.0
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.
- 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?
|