Hello all, I''m using cached fragments to provide feeds from flickr, delicious etc and want these feeds to be updated on site specific times, for example - "If the fragment from flickr is more than 24 hours old refresh it", "If the fragment from delicious is more than 30 minutes old refresj it" Ideally, I don''t want to use a cron job to monitor them because I can''t help but feel that''s a slighly inelegant solution. To my mind the details about the fragments expiry should be linked to it quite tightly. The best solution I''ve been able to come up with is..... class ApplicationController < ActionController::Base def fragment_ok?(name, options = nil) cache_content = read_fragment(name, options) return false unless cache_content cache_content =~ /<!-- expires:([0-9]+)/ ends = $1.to_i now = Time.now.to_i return cache_content if (now < ends) expire_fragment(name, options) return false end end module ApplicationHelper def minutes_til_fragment_expires(minutes_til_death) now = Time.now.to_i expires = now + (60*minutes_til_death) return ''<!-- expires:''+expires.to_s+'' -->'' end end class FlickrController < ApplicationController def recent_photos @fragment_name = ''/flickr/recent_photos'' unless(fragment_ok?(@fragment_name)) # make the call to flickr, set up the variables for the template end end and, finally, in the template begin with <% cache(@fragment_name) do %><%= minutes_til_fragment_expires(24*60) %> the net result is that the flickr fragment looks like <!-- expires:1131270619 --> <h2>blah, blah and I can check the expiry date on the fragment at each request. ######### Is there a simpler way to achieve the same effect but without using daemon processes? Many thanks, and my apologies for posting an open question rather than a specific problem, but I''m the only Rubyist in my company so I''ve no-one to talk to ;-( Gav
Gavin Montague wrote:> Hello all, > I''m using cached fragments to provide feeds from flickr, > delicious etc and want these feeds to be updated on site specific > times, for example - "If the fragment from flickr is more than 24 > hours old refresh it", "If the fragment from delicious is more than > 30 minutes old refresj it" > > Ideally, I don''t want to use a cron job to monitor them because I > can''t help but feel that''s a slighly inelegant solution. To my mind > the details about the fragments expiry should be linked to it quite > tightly. > > The best solution I''ve been able to come up with is..... >I can''t see anything wrong with periodically exipring from the command line. Especially with the expiration intervals given as examples above. Checking for expired fragments on each request, will ... slow down your app. -- stefan RailsExpress Blog: http://railsexepress.de/blog
Gav- I don''t think there is anything inelegant with using cron to do time based expiry. I am doing something similar where I need to expire the cache every 1.5 hours. I use a cron job that calls script/runner to expire the cache and it works great. I think what you are doing in your whole explanation is going to cause more problems and is more inelegant itself than using cron for what it is good for, time based actions. Cheers- -Ezra On Nov 5, 2005, at 3:01 AM, Gavin Montague wrote:> Hello all, > I''m using cached fragments to provide feeds from flickr, > delicious etc and want these feeds to be updated on site specific > times, for example - "If the fragment from flickr is more than 24 > hours old refresh it", "If the fragment from delicious is more than > 30 minutes old refresj it" > > Ideally, I don''t want to use a cron job to monitor them because I > can''t help but feel that''s a slighly inelegant solution. To my > mind the details about the fragments expiry should be linked to it > quite tightly. > > The best solution I''ve been able to come up with is..... > > class ApplicationController < ActionController::Base > def fragment_ok?(name, options = nil) > cache_content = read_fragment(name, options) > return false unless cache_content > cache_content =~ /<!-- expires:([0-9]+)/ > ends = $1.to_i > now = Time.now.to_i > return cache_content if (now < ends) > expire_fragment(name, options) > return false > end > end > > module ApplicationHelper > def minutes_til_fragment_expires(minutes_til_death) > now = Time.now.to_i > expires = now + (60*minutes_til_death) > return ''<!-- expires:''+expires.to_s+'' -->'' > end > end > > class FlickrController < ApplicationController > def recent_photos > @fragment_name = ''/flickr/recent_photos'' > unless(fragment_ok?(@fragment_name)) > # make the call to flickr, set up the variables for the template > end > end > > and, finally, in the template begin with > > <% cache(@fragment_name) do > %><%= minutes_til_fragment_expires(24*60) %> > > the net result is that the flickr fragment looks like > > <!-- expires:1131270619 --> > <h2>blah, blah > > and I can check the expiry date on the fragment at each request. > > ######### > Is there a simpler way to achieve the same effect but without using > daemon processes? > > Many thanks, and my apologies for posting an open question rather > than a specific problem, but I''m the only Rubyist in my company so > I''ve no-one to talk to ;-( > > > Gav > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-Ezra Zygmuntowicz WebMaster Yakima Herald-Republic Newspaper ezra-gdxLOakOTQ9oetBuM9ipNAC/G2K4zDHf@public.gmane.org 509-577-7732
Perhaps inelegant was the wrong choice of word. I agree with what you say for the most part but my objections to cron are just that: 1. You have to either have multiple jobs or a single job running at the frequency of the smallest cached unit. I''d either need to be running n jobs for n feeds or a single job that ran every, say, 30 minutes and either refreshed all the caches including ones that weren''t stale or had the brains (i.e. more code) to sniff which ones were still fresh. 2. It''s repetitive. Unless I''ve missed something about the way the fragment cache works (entirely possible) there''s no way to say, Script - "So who''s in the Cache?" FragA - "I am!" Script - "Ok, you''ve expired, (Script then gets the name of FragA) so I''ll refresh you" *Script then calls the correct action* Script - "RIght, who''s next?" FragB - "I am!" etc. Which means you need to keep a table of what you render as fragments in the script that cron runs. In other words, it isn''t enough for the controller and the view to handle the cache, you have to repeat that information in the job (maybe I''m taking the DRY principle to far) 3. The schedule is fixed. If I have a view that renders when there''s a network error when I try to grab a feed I might want to try again in 5 minutes as opposed to 30. This means that for 99% of the time I''m running a 5 minute cron job that isn''t doing anything. Just my $0.02, I''m genuinely not trying to be argumentative in an arsey way; Rails is still quite new to me and I''m just thinking aloud. Gav On 5 Nov 2005, at 20:21, Ezra Zygmuntowicz wrote:> Gav- > > I don''t think there is anything inelegant with using cron to do > time based expiry. I am doing something similar where I need to > expire the cache every 1.5 hours. I use a cron job that calls > script/runner to expire the cache and it works great. I think what > you are doing in your whole explanation is going to cause more > problems and is more inelegant itself than using cron for what it > is good for, time based actions. > > Cheers- > -Ezra > On Nov 5, 2005, at 3:01 AM, Gavin Montague wrote: > >> Hello all, >> I''m using cached fragments to provide feeds from flickr, >> delicious etc and want these feeds to be updated on site specific >> times, for example - "If the fragment from flickr is more than >> 24 hours old refresh it", "If the fragment from delicious is more >> than 30 minutes old refresj it" >> >> Ideally, I don''t want to use a cron job to monitor them because I >> can''t help but feel that''s a slighly inelegant solution. To my >> mind the details about the fragments expiry should be linked to it >> quite tightly. >> >> The best solution I''ve been able to come up with is..... >> >> class ApplicationController < ActionController::Base >> def fragment_ok?(name, options = nil) >> cache_content = read_fragment(name, options) >> return false unless cache_content >> cache_content =~ /<!-- expires:([0-9]+)/ >> ends = $1.to_i >> now = Time.now.to_i >> return cache_content if (now < ends) >> expire_fragment(name, options) >> return false >> end >> end >> >> module ApplicationHelper >> def minutes_til_fragment_expires(minutes_til_death) >> now = Time.now.to_i >> expires = now + (60*minutes_til_death) >> return ''<!-- expires:''+expires.to_s+'' -->'' >> end >> end >> >> class FlickrController < ApplicationController >> def recent_photos >> @fragment_name = ''/flickr/recent_photos'' >> unless(fragment_ok?(@fragment_name)) >> # make the call to flickr, set up the variables for the template >> end >> end >> >> and, finally, in the template begin with >> >> <% cache(@fragment_name) do >> %><%= minutes_til_fragment_expires(24*60) %> >> >> the net result is that the flickr fragment looks like >> >> <!-- expires:1131270619 --> >> <h2>blah, blah >> >> and I can check the expiry date on the fragment at each request. >> >> ######### >> Is there a simpler way to achieve the same effect but without >> using daemon processes? >> >> Many thanks, and my apologies for posting an open question rather >> than a specific problem, but I''m the only Rubyist in my company so >> I''ve no-one to talk to ;-( >> >> >> Gav >> _______________________________________________ >> Rails mailing list >> Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org >> http://lists.rubyonrails.org/mailman/listinfo/rails >> > > -Ezra Zygmuntowicz > WebMaster > Yakima Herald-Republic Newspaper > ezra-gdxLOakOTQ9oetBuM9ipNAC/G2K4zDHf@public.gmane.org > 509-577-7732 > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails
Actually, I''m beginning to think that cron might be better but for a reason that hasn''t been mentioned. Because I''m forcing the cache refreshs onto visitors requests (and on a low traffic site) then the initial page responses for most people are going to be very slow. At least if it''s being done as a cron job then it''s in the background and therefore transparent to the users. Hmm. G On 5 Nov 2005, at 11:01, Gavin Montague wrote:> Hello all, > I''m using cached fragments to provide feeds from flickr, > delicious etc and want these feeds to be updated on site specific > times, for example - "If the fragment from flickr is more than 24 > hours old refresh it", "If the fragment from delicious is more than > 30 minutes old refresj it" > > Ideally, I don''t want to use a cron job to monitor them because I > can''t help but feel that''s a slighly inelegant solution. To my > mind the details about the fragments expiry should be linked to it > quite tightly. > > The best solution I''ve been able to come up with is..... > > class ApplicationController < ActionController::Base > def fragment_ok?(name, options = nil) > cache_content = read_fragment(name, options) > return false unless cache_content > cache_content =~ /<!-- expires:([0-9]+)/ > ends = $1.to_i > now = Time.now.to_i > return cache_content if (now < ends) > expire_fragment(name, options) > return false > end > end > > module ApplicationHelper > def minutes_til_fragment_expires(minutes_til_death) > now = Time.now.to_i > expires = now + (60*minutes_til_death) > return ''<!-- expires:''+expires.to_s+'' -->'' > end > end > > class FlickrController < ApplicationController > def recent_photos > @fragment_name = ''/flickr/recent_photos'' > unless(fragment_ok?(@fragment_name)) > # make the call to flickr, set up the variables for the template > end > end > > and, finally, in the template begin with > > <% cache(@fragment_name) do > %><%= minutes_til_fragment_expires(24*60) %> > > the net result is that the flickr fragment looks like > > <!-- expires:1131270619 --> > <h2>blah, blah > > and I can check the expiry date on the fragment at each request. > > ######### > Is there a simpler way to achieve the same effect but without using > daemon processes? > > Many thanks, and my apologies for posting an open question rather > than a specific problem, but I''m the only Rubyist in my company so > I''ve no-one to talk to ;-( > > > Gav > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails