GenerationalActionCaching allows applications to easily implement generational action caching. Most of the code is based on the “Accelerate your Rails Site with Automatic Generation-based Action Caching” presentation by Rod Cope of OpenLogic inc. For more information see the presentation available here: en.oreilly.com/oscon2009/public/schedule/detail/8417
None
script/plugin install git://github.com/jkupferman/generational_action_cacher.git
After installing the plugin, add the following to your controller.
include GenerationalActionCaching generational_action_cacher
The initializer takes a few options which allow you to specify some information about how the cache should behave. Note that no options are required by default. The available options are:
-
app_name - The name of the application to avoid collisions with other applications using the same cache (e.g. :app_name => “FOOBAR”)
-
expires_in - How long the entries should stay in the cache. This uses the standard cache expires_in option. (e.g. :expires_in => 1.hour)
-
production_only - Only perform caching when run in the production rails environment. By default it runs in all environments. (e.g. :production_only => true)
-
use_commit_hash - Includes the current commit hash in the cache key. See FAQ for more information on why this is used. It takes in the type of version control system being used, currently only git and svn on *nix are supported. (e.g. :use_commit_hash => :git)
-
cache_only - Only attempt to cache the provided methods (e.g. :cache_only => [:show])
-
cache_except - Cache all (get) methods execept the ones provided (e.g. :cache_except => :index)
-
update_only - Only change the generation for the provided methods (e.g. :update_only => :create)
-
update_except - Change the generation on all (non-get) methods except the ones provided (e.g. :expire_except => [:delete])
1. What is generational caching?
It is a very simple but effective caching strategy for data. The application has a “generation” which is changed each time the application is changed. The generation is included in the cache key such that when it changes it will cause the next cache read to miss and regenerate the data. For example if the generation is currently 1 then all gets will hit the cache while the generation stays the same. When an update happens, the generation is incremented to 2. Thus the next time the data is read it will miss the cache and be regenerated. It should be noted that by default generational caching does not require data to be expired or deleted from the cache since when the generation is changed stale data is no longer accessed.
2. When is the generation changed?
By default the generation is changed on any non-get request (e.g. update, create, destroy). If there are particular actions which you do not want to change the generation they can be specified using the :update_only and :update_except options. For example, if you only want the generation to change when the create action is called then use the following in your controller:
generational_action_cacher :update_only => [:create]
And if you want to update the generation for all (non-get) methods except for the update and destroy actions, use the following:
generational_action_cacher :update_except => [:update,:destroy]
Note, the above would only update the generation upon create if only the standard CRUD operations are available.
3. Why on earth are you using a commit hash? The answer here is a bit subtle. Imagine you have an application which you start and then perform a get on the index action. It will start by initializing the generation to 1 (since it was not in the cache before). Similarly, it will miss the cache for the index action since it was not in the cache before. After generating the page it will be written back into the cache. Next you terminate the application, make a code change to the index action, and then start it again. This time it will fetch the generation (which is still 1) and then it will do a lookup in the cache for the index page. Since the generation has not changed it would fetch the cached index page which was generated prior to the code change. This is probably not what you want and would cause the stale page to be displayed. In order to avoid this issue the current commit hash from the version control system is used to cause the key to change.
4. What if I don’t want to use a commit hash?
Simply do not add the :use_commit_hash option.
5. Does the commit hash update automatically?
For performance reasons the commit hash is only fetched once when the module is loaded. If running in production classes are only loaded once and as a result commit hash will not update until the server (e.g. Mongrel) is restarted.
5. What version control systems are supported?
SVN and git.
6. How do I specify which version control system I am using?
Simply add the name of the vcs you are using to the use_commit_hash option, for example:
generational_action_cacher :use_commit_hash => :svn
or generational_action_cacher :use_commit_hash => :git
7. This is awesome, how can I contribute?
While the plugin works as-is there are still quite a few improvements which could be made. First, adding support for other VCS systems (e.g. bzr) could help. Cleaning up the way the commit hashes are retrieved since it currently would only works on *nix based systems. Of course, adding tests would be greatly appreciated.
Copyright © 2009 [Jonathan Kupferman], released under the MIT license