fastaccess - redisfast access on generated content
Many web applications which provide textual content to the user have much more reads than writes. This can mean, that on every 10k reads there is one write (see some popular blogs or newspages).
Often this content is generated, because the input source is some markup format, like markdown. This means, that there is always the need to generate this content into html.
And this is why fastaccess exists. It modifies any given method, which generates content, and stores it in a redis database. If this content solely depends on a model attribute, for example like the body in a blog post, it will be auto updated, if the underlying model attribute changes. Otherwise you can trigger the update manually.
Now lets see how this works:
Using fastaccess
First, of course, you'll need to include this gem in your projects Gemfile.
Since this gem utilizes redis, make sure that this is installed and generate the default initializer with
rails generate fastaccess:initialize
This will create a file in config/initializers/fastaccess.rb which will create an instance of a redis database-connection. If you already have one of those, feel free to replace the new instance with your version.
Now, in your project you will have to use the gem-provided
acts_with_fastaccess_on
method to mark certain methods
as registered with fastaccess for caching.
class Post < ActiveRecord::Base
attr_accessible :title, :body
acts_with_fastaccess_on :markdown_body
def markdown_body
markdown(self.body)
end
end
In this example a Model named Post is defined which has title and
body attributes. The markdown_body
method converts the markdown-body to
html. Since this is needed often, it cached via redis.
The previous example utilizes a method, which operates on one of the models attributes. So the redis-content will be updated if the pertaining Model instance is updated. But what if you have a method which uses more input than just specific attributes, which will update the models timestamp?
For this case there is an explicit update method, which allows you to trigger an update.
# app/models/post.rb
class Post < ActiveRecord::Base
attr_accessible :title, :body, :tags
has_many :tags
acts_with_fastaccess_on :tag_list
include Fastaccess::Mixins
def tag_list
self.tags.map(&name)
end
end
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def update
@post = Post.find_by_id(params[:id])
@post.update_on :tag_list
respond_to do |format|
if @post.update_attributes(params[:post])
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
If you don't want to pollute your model with these mixin-methods you can also call
Fastaccess::Fastaccess.update_content @post, :on => :tag_list, :arguments => []
Configuring Fastaccess
Initializers
Fastaccess comes with a generator for an initializer file. You can run it by calling:
rails generate fastaccess:initialize
This will create config/initializers/fastaccess.rb
, which allows you to
set the redis-connector instance, which will be used to communicate
with redis. If you've just installed redis and are running
it with default settings, the defaults from the initializer file
should work nicely.
Configure acts_with...
deactivating auto_update
If you need to call update_content
manually (either via the mixin
version or the global one), you probably don't want the unnecessary
updates, which are being triggered by every update on the pertaining
record (and the subsequent method-call). You can deactivate it
for specific method, by passing it via the options hash.
acts_with_fastaccess_on :markdown, :auto_update => false
using multiple generated versions
Since the methods you will use fastaccess on, will usually generate content, it might be possible, that you want to use multiple versions of this content frequently without resorting to another method. You can achieve this by setting argument-groups, which is an array in which each element (an argument group) refers to the arguments passed to the method in this version:
acts_with_fastaccess_on :markdown_with_opts, :versions => [
{prevent_html:true},
{prevent_html:false}
]
This will allow fastaccess to store both versions in the redis database.
Features
planned features
- ~~disable auto-update via option setting (planned for 0.0.2)~~ implemented
- more update flexibility
- e.g. custom update-constraints instead of calling
update_content
manually
- e.g. custom update-constraints instead of calling
- ~~version~~ ~~sometimes parameters passed to the watched method aren't arbitrary, but contain some sort of state. So some output-versions of the generated content are used, with evenly distributed odds. Fastaccess should allow for these versions to exist in memory. This means, that certain sets of arguments are bundling a so called version, which should be accessible via redis for more flexibility.~~ implemented
License
Copyright © 2013:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.