Ruby on Rails
Sunday, May 25, 2014
On Saturday, May 24, 2014 6:48:50 PM UTC-4, Kai Krakow wrote:
Hello list!
I need to expire fragment caches from a background job. The usual way to
expire caches is to create a cache sweeper and put the observer hooks into
the controller. That is fine as long as database is only modified through
controller actions.
But in this case I have a background job importing data, and that needs to
invalidate fragment caches for records it touches. The most elegant way
would be to able to install the sweeping observer while the background job
is running so it will expire all touched object's caches.
Thinking further, sometimes from the Rails console, I'm starting manual
imports by invoking MyModel.import_all! on the model that's going to import
data. Now, how would caches be expired here? Clearly, the MVC way cannot
work here.
Time to break the rules. So, what would be the best approach to handle this?
I'm seeing three ways with different downsides but only one that would solve
the problem:
1. Expire fragments through observers the MVC way
Downside: Background importers won't purge caches because only
controllers install sweepers/observers.
Conclusion: This is no option.
2. Expire fragments through observers installed in controllers and
background jobs
Downside: No sweeping when running imports from console.
Conclusion: Probably the cleanest solution but not a real option.
3. Expire fragments directly from the models
Downside: Not the proposed MVC way, no support in Rails framework.
Conclusion: The only solution that works in a DRY way for me.
Looking at these points, I question the whole design behind sweepers and
their MVC voodoo. Trying to force cache sweeping into controllers only is
somehow a failed design. I don't see why that is. In the end, it's the data
that makes up the views. Why should a controller sweep its caches? Is it for
performance reasons? Clearly it cannot be the choice about clearing its own
views because other controllers could show results from the same models.
I often end up purging the caches from all controllers within the observer.
While that is DRY it shows the misconception about making sweepers available
to controllers only.
--
Replies to list only preferred.
A couple of responses. First, in Rails 4 this was changed. It now incorporates generational caching. The cache key has a digest which is a hash of the underlying template content so that any changes in content will bust the cache automatically. Observers have actually been removed from Rails 4 although you can still get the functionality back by using a gem.
Second, the architecture did make sense initially. In your typical Rails app, you don't want your database updated without going through the controller. Even interfaces from other applications are, ideally, processed through an API as json or xml. Caching is the least of the issues, you want to insure that all the constraints and security established in the controller and model are applied. Fragment caching is actually a view process and, in MVS, you don't want to manage view processes from the model, the controller is designed to be the one to generate messages from one to the other. Therefore, you used to generally have the Controller generate a message to the view when there's a change in the underlying model that affect it. By the way, there are things other than data that can change a view fragment. In particular, a change in image file references that get incorporated into the view come to mind.
There are always situations that won't fit into this, although they are usually the exception and not the rule. You could have a resource that you maintain only for information and gets updated on some periodic basis by a batch import. In that case, you are correct, you either have to define a method within the model (which is most common) that may cross the boundaries a bit.
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe@googlegroups.com.
To post to this group, send email to rubyonrails-talk@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/1519781a-6f96-4d11-8ba1-640c7f9b51b8%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment