Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Helper for fragment caching server rendered react components #39

Closed
justin808 opened this issue Sep 26, 2015 · 13 comments
Closed

Helper for fragment caching server rendered react components #39

justin808 opened this issue Sep 26, 2015 · 13 comments

Comments

@justin808
Copy link
Member

If only the JS code change, then the cache will not be invalidated. Possible solutions to the problem include:

  1. Always invalidate the whole cache on pushes. Trivial.
  2. Only invalidate the React server rendering caches on pushes. This can be done by including the git deployment sha string in the cache key. Very easy.
  3. Manually add a string to the cache key indicating a version and update that key when this needs to change. This is easy, but it can be error prone.
  4. Have the view helper render_component support caching of components and be able to resolve dependencies. This is relatively more difficult as it involves determining a dependency tree of what went into the component.

This is how Rails does it for views.
https://github.com/rails/cache_digests/tree/master/lib/cache_digests

@andreasklinger
Copy link

We add the hash of the webpack main.js and the hash of the serializers to the cache checksum

    def fetch_component(name, args, options, &block)
      Rails.cache.fetch [webpack_checksum, name, Digest::SHA1.hexdigest(args.to_s), options], &block
    end

    def serializer_checksum
      return @serializer_checksum if @serializer_checksum.present? && !Rails.env.development?

      digest = Digest::SHA1.new
      serializer_files.each { |f| digest.file(f) }
      @serializer_checksum = digest.hexdigest
    end

    private

    def serializer_files
      Dir.glob(Rails.root.join('app/serializers/**/*.rb'))
    end

    def webpack_checksum
      return @webpack_checksum if @webpack_checksum.present? && !Rails.env.development?

      @webpack_checksum = Digest::SHA1.file(Webpack.local_asset_path('main.js')).hexdigest
    end

better ideas welcome

@justin808
Copy link
Member Author

@andreasklinger Looking at the code, I'm guessing that you include the serializers because your "args" are not the JSON props (Hash or String) being passed to the component. Any chance that you could elaborate more on your inclusion on the serializers and if there were any performance hot spots in computing the digests.

@justin808
Copy link
Member Author

Hash Speed

Interesting discussion here:

  1. http://stackoverflow.com/questions/3665247/fastest-hash-for-non-cryptographic-uses
  2. http://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed
 Name            Speed       Q.Score   Author
 xxHash          5.4 GB/s     10
 MumurHash 3a    2.7 GB/s     10       Austin Appleby
 SpookyHash      2.0 GB/s     10       Bob Jenkins
 SBox            1.4 GB/s      9       Bret Mulvey
 Lookup3         1.2 GB/s      9       Bob Jenkins
 CityHash64      1.05 GB/s    10       Pike & Alakuijala
 FNV             0.55 GB/s     5       Fowler, Noll, Vo
 CRC32           0.43 GB/s     9
 MD5-32          0.33 GB/s    10       Ronald L. Rivest
 SHA1-32         0.28 GB/s    10

xxHash

Possibly xxhash could help?

Background articles

Rails Source Code References

@andreasklinger

  1. Did the hashing come up as any performance bottleneck? Rails source uses md5, google search reveals that fastest might now be xxhash.
  2. Look at your code again, I'm guessing that the "args" are whatever makes sense for your caching and not necessarily what's used for computing the props.
  3. It's clever how you preserve the cache if your main.js stays the same along with all your serializers.

@justin808
Copy link
Member Author

We'll add a view helper method for creating a cache key in the near future. This will be a nice addition for this gem.

@justin808 justin808 changed the title Need a strategy for rails fragment cache invalidation Helper for fragment caching server rendered react components Sep 27, 2015
@lfittl
Copy link

lfittl commented Sep 27, 2015

@justin808 You are correct that we choose to use the args vs the serializer output because of the slowness of computing the hash (I'm the one who wrote that code, its been a few months though).

This was especially obvious when you assume that both the cache output and the pre-render output are cached (based on the same initial serializer input args), in this case you'd want to minimize overhead.

However I think it'd be fine to re-evaluate the use of a hash method here - I think we tried sha1sum of the JSON serializer output at one point, but using the original arguments was the easier choice.

@justin808
Copy link
Member Author

@robwise @alexfedoseev @dylangrafmyre This "issue" is relevant for our upcoming incorporation of fragment caching. We should aim to create a generic helper function, possibly part of our upcoming "React on Rails Pro" premium subscription.

@justin808
Copy link
Member Author

This will be solved by the hashes of the files from webpacker. The key is that the JS bundles will have to be separated, and the cache call will requiring specifying the dependent bundles.

@corsonknowles
Copy link

What's the status on this? I am investigating memory issue (~leak) in our app coming from gems and have narrowed it to either this or Delayed Jobs

Reference: https://github.com/ASoftCo/leaky-gems/blob/master/README.md

@justin808
Copy link
Member Author

@corsonknowles A helper for caching is definitely doable. We haven't had enough users like you asking for it.

I'd be happy to work with you on this if you like.

I don't have any comment on the memory leak other than tons of apps are live on React on Rails and nobody is blaming it.

@corsonknowles
Copy link

Thanks! Our memory issue spontaneously resolved during refactoring to move to Rails 5.1.4, but it was almost certainly related to Delayed Jobs and not server rendering.

@mapreal19
Copy link
Member

what about having the react component helper to support caching (passing cache: true)?

cc @robwise @justin808

@robwise
Copy link
Contributor

robwise commented Feb 7, 2018

I think it's a good idea, that way checking the server bundle can be done automatically under the hood if cache: true and prerender: true are both passed.

@shakacode shakacode deleted a comment from mapreal19 Apr 21, 2018
@justin808
Copy link
Member Author

Caching is a part of React on Rails Pro. Contact justin@shakacode.com for more info.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants