SlideShare a Scribd company logo
1 of 91
Page Caching Resurrected

Ben Sco eld – Viget Labs
Page Caching Resurrected:
A Fairy Tale
Ben Sco eld – Viget Labs
three little pigs
three little pigs
page caching
class PigsController
 caches_page :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_page :action => :show
 end
end
class PigsController
 caches_page :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_page :action => :show
 end
end
class PigsController
 caches_page :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_page :action => :show
 end
end
standard   1




   page    3000




                  requests per second
public
dynamic
content
action caching
class PigsController
 require_login :show
 caches_action :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_action :action => :show
 end
end
class PigsController
 require_login :show
 caches_action :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_action :action => :show
 end
end
class PigsController
 require_login :show
 caches_action :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_action :action => :show
 end
end
standard   1



  action   500



   page    3000




                  requests per second
dynamic
content
fragment caching
<% cache(:key => 'index:piglist') do %>
 <ul id=quot;pig-listquot;>
  <% @pigs.each do |pig| %>
   <li>
     <%= image_tag pig.house.photo %>
     <%= h pig.name %>
   </li>
  <% end %>
 </ul>
<% end %>
<% cache(:key => 'index:piglist') do %>
 <ul id=quot;pig-listquot;>
  <% @pigs.each do |pig| %>
   <li>
     <%= image_tag pig.house.photo %>
     <%= h pig.name %>
   </li>
  <% end %>
 </ul>
<% end %>
class PigsController
 # ...

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_fragment :key => 'index:piglist'
 end
end
class PigsController
 # ...

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_fragment :key => 'index:piglist'
 end
end
standard   1


fragment   20


  action   500


   page    3000




                  requests per second
eficiency
the idea
Rails 2.3
hello, metal
class BigBadWolf
 def self.call(env)
   if env[quot;PATH_INFOquot;] =~ /^/threaten/
     [
       200,
       {quot;Content-Typequot; = quot;text/htmlquot;},
       quot;Little pig, little pig, let me in!quot;
     ]
   else
     [
       404,
       {quot;Content-Typequot; = quot;text/htmlquot;},
       quot;Not Foundquot;
     ]
   end
 end
end
high-performance endpoints
AJAX
so...
javascript
ul id=quot;logged-out-navquot; class=quot;usernavquot; style=quot;display:nonequot;
 li class=quot;first sign-out-linkquot;
  a class=quot;utility-linkquot; href=quot;#quot; id=quot;login-linkquot;
     onclick=quot;Login.show($('top-login-form')); return false;quot;Login/a
 /li
 li class=quot;signin-border-leftquot;
  a href=quot;/users/forgot_passwordquot; class=quot;utility-linkquot;Forgot Password?/a
 /li
 li class=quot;signin-border-leftquot;
  a href=quot;/signupquot; class=quot;utility-linkquot;Sign Up/a
 /li
/ul
div id=quot;top-login-formquot; class=quot;usernav login-formquot; style=quot;display:nonequot;
 form action=quot;https://secure.hulu.com/account/authenticatequot;
   method=quot;getquot; name=quot;login-formquot; onsubmit=quot;Login.submit(this); return false;quot;
  span class=quot;login-statusquot;/span
  input id=quot;loginquot; class=quot;active loginquot; type=quot;textquot;
   style=quot;display: none;quot; name=quot;usernamequot;/
  input id=quot;passwordquot; class=quot;active passwordquot; type=quot;passwordquot;
   style=quot;display: none;quot; name=quot;passwordquot;/
  input class=quot;inactive dummy loginquot; type=quot;textquot; value=quot;usernamequot;
   name=quot;dummy_loginquot; /
  input class=quot;inactive dummyquot; type=quot;textquot; value=quot;passwordquot; name=quot;dummy_passwordquot; /
  input alt=quot;Loginquot; class=quot;login-submitquot;
   src=quot;http://static.hulu.com/images/btn-signin-small.gif?1237361096quot;
   style=quot;width: 39px; height: 20;quot; type=quot;imagequot; /
  a href=quot;#quot;img alt=quot;Cancelquot; border=quot;0quot; class=quot;hover-mequot; height=quot;20quot;
   id=quot;btn-x.gif123741536309506quot; onclick=quot;Login.cancel();return falsequot;
   src=quot;http://static.hulu.com/images/btn-x.gif?1237361096quot; width=quot;18quot; //a
 /form

 a href=quot;/signupquot; class=quot;utility-linkquot;Sign Up/a
/div
ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;
 li id=quot;welcome-usernamequot; class=quot;firstquot;
  Welcome
 /li

 li
  a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a
 /li

 li
  a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a
 /li

 li class=quot;sign-out-linkquot;
  a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a
 /li
/ul
noscript
 ul class=quot;nojs usernavquot;
  li
   Please a href=quot;/support/quot;enable javascript/a to log in.
  /li
 /ul
/noscript
script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/
 Event.observe(window, quot;loadquot;, function() {
   Behaviors.onLoad();
   Behaviors.setLoggedIn();
   Login.setup();
   if ($(quot;loginquot;)  $(quot;login-formquot;)) {
     Event.observe('login', 'keydown', function(ev) {
       if (ev.keyCode == 13) { Login.submit(); }
     });
   }
 });
 Login.auth = function(login, password) {
   document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ...
   document.cookie = 'password=' + password + '; path=/account/authenticate; ...
   el = $$('body').first();
   if (el) {
     var script = document.createElement('script');
     script.type = 'text/javascript';
     script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ...
     el.appendChild(script);
   }
 }
/*]]*//script
ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;
 li id=quot;welcome-usernamequot; class=quot;firstquot;
  Welcome
 /li

 li
  a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a
 /li

 li
  a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a
 /li

 li class=quot;sign-out-linkquot;
  a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a
 /li
/ul
ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;
 li id=quot;welcome-usernamequot; class=quot;firstquot;
  Welcome
 /li

 li
  a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a
 /li

 li
  a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a
 /li

 li class=quot;sign-out-linkquot;
  a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a
 /li
/ul
hulu is insane
 don’t do it like they do
script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/
 Event.observe(window, quot;loadquot;, function() {
   Behaviors.onLoad();
   Behaviors.setLoggedIn();
   Login.setup();
   if ($(quot;loginquot;)  $(quot;login-formquot;)) {
     Event.observe('login', 'keydown', function(ev) {
       if (ev.keyCode == 13) { Login.submit(); }
     });
   }
 });
 Login.auth = function(login, password) {
   document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ...
   document.cookie = 'password=' + password + '; path=/account/authenticate; ...
   el = $$('body').first();
   if (el) {
     var script = document.createElement('script');
     script.type = 'text/javascript';
     script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ...
     el.appendChild(script);
   }
 }
/*]]*//script
script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/
 Event.observe(window, quot;loadquot;, function() {
   Behaviors.onLoad();
   Behaviors.setLoggedIn();
   Login.setup();
   if ($(quot;loginquot;)  $(quot;login-formquot;)) {
     Event.observe('login', 'keydown', function(ev) {
       if (ev.keyCode == 13) { Login.submit(); }
     });
   }
 });
 Login.auth = function(login, password) {
   document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ...
   document.cookie = 'password=' + password + '; path=/account/authenticate; ...
   el = $$('body').first();
   if (el) {
     var script = document.createElement('script');
     script.type = 'text/javascript';
     script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ...
     el.appendChild(script);
   }
 }
/*]]*//script
the* right way


      *a
the standard approach
class ItemsController  ApplicationController
 def index
   @user = User.find_by_login(params[:user])
   @items = Item.released_on(params[:date])
 end
end
class Item  ActiveRecord::Base
 has_many :pulls, :dependent = :destroy

 named_scope :released_on, lambda { |date|
   date ||= Item.maximum(:released_on)
   {:conditions = {:released_on = date}, :order = 'name ASC'}
 }

 def pulled_by?(user)
  x = user.nil? ? false : !self.pulls.by_user(user.id).empty?
 end
end
h1Releases/h1

ul
 % @items.each do |item| %
  % content_tag_for :li, item do %
   %= image_tag 'cover.png', :alt = h(item.name), :class = 'cover' %
   %= image_tag('badge.png', :alt = 'pulling',:class = 'badge')
      if item.pulled_by?(@user) %
   p%= h item.name %/p
  % end %
 % end %
/ul
the hybrid approach
class ItemsController  ApplicationController
 caches_page :index

 def index
  @items = Item.released_on(params[:date]).all
 end
end
require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless
 defined?(Rails)

class PullList
 def self.call(env)
   if env[quot;PATH_INFOquot;] =~ /^/pulls/
     date = '2008-11-05'
     user = '1'
     [
       200,
      {quot;Content-Typequot; = quot;application/javascriptquot;},
      [Pull.by_user(user).for_date(date).map {|i| i.item_id}.to_json]]
   else
     [404, {quot;Content-Typequot; = quot;text/htmlquot;}, [quot;Not Foundquot;]]
   end
 end
end
class Pull  ActiveRecord::Base
 belongs_to :user
 belongs_to :item

 named_scope :by_user, lambda { |user_id|
   {:conditions = {:user_id = user_id}}
 }
 named_scope :for_date, lambda { |date|
   {:include = :item, :conditions = {:items = {:released_on = date}}}
 }
end
$(document).ready(function() {
  $.getJSON('/pulls', function(data) {
    $.each(data, function() {
      $('#item_'+this).addClass('pulled');
    });
  });
});
standard
hybrid
standard   0.617




  hybrid   0.039 0.096




                         content load time
hybrid approach - version 2
class SessionsController  ApplicationController
 def new; end

 def create
  # ...
  session[:pulls] = @user.pulls.map {|i| i.item_id}
  redirect_to items_path
 end
end
require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless
 defined?(Rails)

class PullList
 def self.call(env)
   if env[quot;PATH_INFOquot;] =~ /^/pulls/
     date = '2008-11-05'
     user = '1'
     [
       200,
       {quot;Content-Typequot; = quot;application/javascriptquot;},
       [env['rack.session'][:pulls].to_json]
     ]
   else
     [404, {quot;Content-Typequot; = quot;text/htmlquot;}, [quot;Not Foundquot;]]
   end
 end
end
hybrid v2
standard    0.617



  hybrid    0.039 0.096



hybrid v2   0.043 0.023




                          content load time
when to use it
when not to use it
accessibility
accessibility
noscript
 ul class=quot;nojs usernavquot;
  li
   Please a href=quot;/support/quot;enable javascript/a to log in.
  /li
 /ul
/noscript
Thank You
ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/bsco eld

More Related Content

What's hot

シックス・アパート・フレームワーク
シックス・アパート・フレームワークシックス・アパート・フレームワーク
シックス・アパート・フレームワーク
Takatsugu Shigeta
 
Rails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity PresentationRails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity Presentation
railsconf
 
Your Custom WordPress Admin Pages Suck
Your Custom WordPress Admin Pages SuckYour Custom WordPress Admin Pages Suck
Your Custom WordPress Admin Pages Suck
Anthony Montalbano
 
网站无障碍阅读知识
网站无障碍阅读知识网站无障碍阅读知识
网站无障碍阅读知识
ppanyong
 
The project gutenberg e book, fairy tales from brazil, by elsie spicer
The project gutenberg e book, fairy tales from brazil, by elsie spicerThe project gutenberg e book, fairy tales from brazil, by elsie spicer
The project gutenberg e book, fairy tales from brazil, by elsie spicer
Andrei Hortúa
 

What's hot (20)

Plone Interactivity
Plone InteractivityPlone Interactivity
Plone Interactivity
 
シックス・アパート・フレームワーク
シックス・アパート・フレームワークシックス・アパート・フレームワーク
シックス・アパート・フレームワーク
 
Web Security Mistakes: Trusting The Client
Web Security Mistakes: Trusting The ClientWeb Security Mistakes: Trusting The Client
Web Security Mistakes: Trusting The Client
 
Rails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity PresentationRails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity Presentation
 
Stole16
Stole16Stole16
Stole16
 
IBM Lotus Notes Domino XPages and XPages for Mobile
IBM Lotus Notes Domino XPages and XPages for MobileIBM Lotus Notes Domino XPages and XPages for Mobile
IBM Lotus Notes Domino XPages and XPages for Mobile
 
DevDays09 Internet Explorer 8
DevDays09 Internet Explorer 8DevDays09 Internet Explorer 8
DevDays09 Internet Explorer 8
 
Fast by Default
Fast by DefaultFast by Default
Fast by Default
 
Your Custom WordPress Admin Pages Suck
Your Custom WordPress Admin Pages SuckYour Custom WordPress Admin Pages Suck
Your Custom WordPress Admin Pages Suck
 
Spring 2.0
Spring 2.0Spring 2.0
Spring 2.0
 
网站无障碍阅读知识
网站无障碍阅读知识网站无障碍阅读知识
网站无障碍阅读知识
 
Presentasi Kelompok 25 PW A+B
Presentasi Kelompok 25 PW A+BPresentasi Kelompok 25 PW A+B
Presentasi Kelompok 25 PW A+B
 
SlideShare Instant
SlideShare InstantSlideShare Instant
SlideShare Instant
 
Tugas pw [kelompok 25]
Tugas pw [kelompok 25]Tugas pw [kelompok 25]
Tugas pw [kelompok 25]
 
SlideShare Instant
SlideShare InstantSlideShare Instant
SlideShare Instant
 
Spring 2.0
Spring 2.0Spring 2.0
Spring 2.0
 
Make Everyone a Tester: Natural Language Acceptance Testing
Make Everyone a Tester: Natural Language Acceptance TestingMake Everyone a Tester: Natural Language Acceptance Testing
Make Everyone a Tester: Natural Language Acceptance Testing
 
10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]
10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]
10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]
 
The project gutenberg e book, fairy tales from brazil, by elsie spicer
The project gutenberg e book, fairy tales from brazil, by elsie spicerThe project gutenberg e book, fairy tales from brazil, by elsie spicer
The project gutenberg e book, fairy tales from brazil, by elsie spicer
 
spring_jiaocheng
spring_jiaochengspring_jiaocheng
spring_jiaocheng
 

Viewers also liked

Viewers also liked (6)

Ciclo 13
Ciclo 13Ciclo 13
Ciclo 13
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
 
Cleanliness is Next to Domain-Specificity
Cleanliness is Next to Domain-SpecificityCleanliness is Next to Domain-Specificity
Cleanliness is Next to Domain-Specificity
 
Resourceful Plugins
Resourceful PluginsResourceful Plugins
Resourceful Plugins
 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUG
 
How to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 StepsHow to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 Steps
 

Similar to Page Caching Resurrected

Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On Rails
Wen-Tien Chang
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
Yi-Ting Cheng
 

Similar to Page Caching Resurrected (20)

Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On Rails
 
Front End on Rails
Front End on RailsFront End on Rails
Front End on Rails
 
Merb jQuery
Merb jQueryMerb jQuery
Merb jQuery
 
Rugalytics | Ruby Manor Nov 2008
Rugalytics | Ruby Manor Nov 2008Rugalytics | Ruby Manor Nov 2008
Rugalytics | Ruby Manor Nov 2008
 
Ajax
AjaxAjax
Ajax
 
Pluginが広げるRailsの魅力
Pluginが広げるRailsの魅力Pluginが広げるRailsの魅力
Pluginが広げるRailsの魅力
 
Ajax On S2 Odp
Ajax On S2 OdpAjax On S2 Odp
Ajax On S2 Odp
 
Ajax ons2
Ajax ons2Ajax ons2
Ajax ons2
 
Javascript Basic
Javascript BasicJavascript Basic
Javascript Basic
 
A rel
A relA rel
A rel
 
Seam Glassfish Slidecast
Seam Glassfish SlidecastSeam Glassfish Slidecast
Seam Glassfish Slidecast
 
JSP Custom Tags
JSP Custom TagsJSP Custom Tags
JSP Custom Tags
 
Widgets Tools Keynote
Widgets Tools KeynoteWidgets Tools Keynote
Widgets Tools Keynote
 
Django - Framework web para perfeccionistas com prazos
Django - Framework web para perfeccionistas com prazosDjango - Framework web para perfeccionistas com prazos
Django - Framework web para perfeccionistas com prazos
 
Couch Db.0.9.0.Pub
Couch Db.0.9.0.PubCouch Db.0.9.0.Pub
Couch Db.0.9.0.Pub
 
Haml & Sass presentation
Haml & Sass presentationHaml & Sass presentation
Haml & Sass presentation
 
Microsoft ASP.NET 4.0 : What's Next?
Microsoft ASP.NET 4.0 : What's Next?Microsoft ASP.NET 4.0 : What's Next?
Microsoft ASP.NET 4.0 : What's Next?
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
Struts2
Struts2Struts2
Struts2
 
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
 

More from Ben Scofield

More from Ben Scofield (20)

Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers Steal
 
Thinking Small
Thinking SmallThinking Small
Thinking Small
 
Open Source: A Call to Arms
Open Source: A Call to ArmsOpen Source: A Call to Arms
Open Source: A Call to Arms
 
Ship It
Ship ItShip It
Ship It
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud Castles
 
Intentionality: Choice and Mastery
Intentionality: Choice and MasteryIntentionality: Choice and Mastery
Intentionality: Choice and Mastery
 
Mastery or Mediocrity
Mastery or MediocrityMastery or Mediocrity
Mastery or Mediocrity
 
With a Mighty Hammer
With a Mighty HammerWith a Mighty Hammer
With a Mighty Hammer
 
Mind Control - DevNation Atlanta
Mind Control - DevNation AtlantaMind Control - DevNation Atlanta
Mind Control - DevNation Atlanta
 
Understanding Mastery
Understanding MasteryUnderstanding Mastery
Understanding Mastery
 
Mind Control: Psychology for the Web
Mind Control: Psychology for the WebMind Control: Psychology for the Web
Mind Control: Psychology for the Web
 
The State of NoSQL
The State of NoSQLThe State of NoSQL
The State of NoSQL
 
NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010
 
NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)
 
Charlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardCharlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is Hard
 
The Future of Data
The Future of DataThe Future of Data
The Future of Data
 
WindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardWindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is Hard
 
"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases
 
Mind Control on the Web
Mind Control on the WebMind Control on the Web
Mind Control on the Web
 
How the Geeks Inherited the Earth
How the Geeks Inherited the EarthHow the Geeks Inherited the Earth
How the Geeks Inherited the Earth
 

Recently uploaded

Call Girls Service In Zirakpur ❤️🍑 7837612180 👄🫦Independent Escort Service Zi...
Call Girls Service In Zirakpur ❤️🍑 7837612180 👄🫦Independent Escort Service Zi...Call Girls Service In Zirakpur ❤️🍑 7837612180 👄🫦Independent Escort Service Zi...
Call Girls Service In Zirakpur ❤️🍑 7837612180 👄🫦Independent Escort Service Zi...
Sheetaleventcompany
 
Zirakpur Call Girls ✅ Just Call ☎ 9878799926☎ Call Girls Service In Mohali Av...
Zirakpur Call Girls ✅ Just Call ☎ 9878799926☎ Call Girls Service In Mohali Av...Zirakpur Call Girls ✅ Just Call ☎ 9878799926☎ Call Girls Service In Mohali Av...
Zirakpur Call Girls ✅ Just Call ☎ 9878799926☎ Call Girls Service In Mohali Av...
rajveerescorts2022
 
Gorgeous Call Girls In Jaipur {9521753030} ❤️VVIP ANKITA Call Girl in Jaipur ...
Gorgeous Call Girls In Jaipur {9521753030} ❤️VVIP ANKITA Call Girl in Jaipur ...Gorgeous Call Girls In Jaipur {9521753030} ❤️VVIP ANKITA Call Girl in Jaipur ...
Gorgeous Call Girls In Jaipur {9521753030} ❤️VVIP ANKITA Call Girl in Jaipur ...
Sheetaleventcompany
 
💚Call Girl In Amritsar 💯Anvi 📲🔝8725944379🔝Amritsar Call Girls No💰Advance Cash...
💚Call Girl In Amritsar 💯Anvi 📲🔝8725944379🔝Amritsar Call Girls No💰Advance Cash...💚Call Girl In Amritsar 💯Anvi 📲🔝8725944379🔝Amritsar Call Girls No💰Advance Cash...
💚Call Girl In Amritsar 💯Anvi 📲🔝8725944379🔝Amritsar Call Girls No💰Advance Cash...
Sheetaleventcompany
 
PREET❤️Call girls in Jalandhar ☎️8264406502☎️ Call Girl service in Jalandhar☎...
PREET❤️Call girls in Jalandhar ☎️8264406502☎️ Call Girl service in Jalandhar☎...PREET❤️Call girls in Jalandhar ☎️8264406502☎️ Call Girl service in Jalandhar☎...
PREET❤️Call girls in Jalandhar ☎️8264406502☎️ Call Girl service in Jalandhar☎...
Sheetaleventcompany
 

Recently uploaded (20)

Call Girls Service In Zirakpur ❤️🍑 7837612180 👄🫦Independent Escort Service Zi...
Call Girls Service In Zirakpur ❤️🍑 7837612180 👄🫦Independent Escort Service Zi...Call Girls Service In Zirakpur ❤️🍑 7837612180 👄🫦Independent Escort Service Zi...
Call Girls Service In Zirakpur ❤️🍑 7837612180 👄🫦Independent Escort Service Zi...
 
Just Call Vip call girls Etawah Escorts ☎️8617370543 Two shot with one girl (...
Just Call Vip call girls Etawah Escorts ☎️8617370543 Two shot with one girl (...Just Call Vip call girls Etawah Escorts ☎️8617370543 Two shot with one girl (...
Just Call Vip call girls Etawah Escorts ☎️8617370543 Two shot with one girl (...
 
Introduction to Fashion Designing for all
Introduction to Fashion Designing for allIntroduction to Fashion Designing for all
Introduction to Fashion Designing for all
 
Call Girls In Mumbai Just Genuine Call ☎ 7738596112✅ Call Girl Andheri East P...
Call Girls In Mumbai Just Genuine Call ☎ 7738596112✅ Call Girl Andheri East P...Call Girls In Mumbai Just Genuine Call ☎ 7738596112✅ Call Girl Andheri East P...
Call Girls In Mumbai Just Genuine Call ☎ 7738596112✅ Call Girl Andheri East P...
 
Escorts Service Model Basti 👉 Just CALL ME: 8617697112 💋 Call Out Call Both W...
Escorts Service Model Basti 👉 Just CALL ME: 8617697112 💋 Call Out Call Both W...Escorts Service Model Basti 👉 Just CALL ME: 8617697112 💋 Call Out Call Both W...
Escorts Service Model Basti 👉 Just CALL ME: 8617697112 💋 Call Out Call Both W...
 
Zirakpur Call Girls ✅ Just Call ☎ 9878799926☎ Call Girls Service In Mohali Av...
Zirakpur Call Girls ✅ Just Call ☎ 9878799926☎ Call Girls Service In Mohali Av...Zirakpur Call Girls ✅ Just Call ☎ 9878799926☎ Call Girls Service In Mohali Av...
Zirakpur Call Girls ✅ Just Call ☎ 9878799926☎ Call Girls Service In Mohali Av...
 
UNIVERSAL HUMAN VALUES - INTRODUCTION TO VALUE EDUCATION
 UNIVERSAL HUMAN VALUES - INTRODUCTION TO VALUE EDUCATION UNIVERSAL HUMAN VALUES - INTRODUCTION TO VALUE EDUCATION
UNIVERSAL HUMAN VALUES - INTRODUCTION TO VALUE EDUCATION
 
Tirunelveli Escorts Service Girl ^ 9332606886, WhatsApp Anytime Tirunelveli
Tirunelveli Escorts Service Girl ^ 9332606886, WhatsApp Anytime TirunelveliTirunelveli Escorts Service Girl ^ 9332606886, WhatsApp Anytime Tirunelveli
Tirunelveli Escorts Service Girl ^ 9332606886, WhatsApp Anytime Tirunelveli
 
Payal Mehta 9867746289, Escorts Service Near The Taj Mahal Palace Colaba
Payal Mehta 9867746289, Escorts Service Near The Taj Mahal Palace ColabaPayal Mehta 9867746289, Escorts Service Near The Taj Mahal Palace Colaba
Payal Mehta 9867746289, Escorts Service Near The Taj Mahal Palace Colaba
 
The Clean Living Project Episode 17 - Blue Zones
The Clean Living Project Episode 17 - Blue ZonesThe Clean Living Project Episode 17 - Blue Zones
The Clean Living Project Episode 17 - Blue Zones
 
Ladies kitty party invitation messages and greetings.pdf
Ladies kitty party invitation messages and greetings.pdfLadies kitty party invitation messages and greetings.pdf
Ladies kitty party invitation messages and greetings.pdf
 
UNIVERSAL HUMAN VALUES -Harmony in the Human Being
UNIVERSAL HUMAN VALUES -Harmony in the Human BeingUNIVERSAL HUMAN VALUES -Harmony in the Human Being
UNIVERSAL HUMAN VALUES -Harmony in the Human Being
 
Tinted Sunscreen For Soft and Smooth Skin
Tinted Sunscreen For Soft and Smooth SkinTinted Sunscreen For Soft and Smooth Skin
Tinted Sunscreen For Soft and Smooth Skin
 
Yamunanagar Escorts Service Girl ^ 9332606886, WhatsApp Anytime Yamunanagar
Yamunanagar Escorts Service Girl ^ 9332606886, WhatsApp Anytime YamunanagarYamunanagar Escorts Service Girl ^ 9332606886, WhatsApp Anytime Yamunanagar
Yamunanagar Escorts Service Girl ^ 9332606886, WhatsApp Anytime Yamunanagar
 
📞 Contact Number 8617370543VIP Hardoi Call Girls
📞 Contact Number 8617370543VIP Hardoi Call Girls📞 Contact Number 8617370543VIP Hardoi Call Girls
📞 Contact Number 8617370543VIP Hardoi Call Girls
 
Gorgeous Call Girls In Jaipur {9521753030} ❤️VVIP ANKITA Call Girl in Jaipur ...
Gorgeous Call Girls In Jaipur {9521753030} ❤️VVIP ANKITA Call Girl in Jaipur ...Gorgeous Call Girls In Jaipur {9521753030} ❤️VVIP ANKITA Call Girl in Jaipur ...
Gorgeous Call Girls In Jaipur {9521753030} ❤️VVIP ANKITA Call Girl in Jaipur ...
 
💚Call Girl In Amritsar 💯Anvi 📲🔝8725944379🔝Amritsar Call Girls No💰Advance Cash...
💚Call Girl In Amritsar 💯Anvi 📲🔝8725944379🔝Amritsar Call Girls No💰Advance Cash...💚Call Girl In Amritsar 💯Anvi 📲🔝8725944379🔝Amritsar Call Girls No💰Advance Cash...
💚Call Girl In Amritsar 💯Anvi 📲🔝8725944379🔝Amritsar Call Girls No💰Advance Cash...
 
PREET❤️Call girls in Jalandhar ☎️8264406502☎️ Call Girl service in Jalandhar☎...
PREET❤️Call girls in Jalandhar ☎️8264406502☎️ Call Girl service in Jalandhar☎...PREET❤️Call girls in Jalandhar ☎️8264406502☎️ Call Girl service in Jalandhar☎...
PREET❤️Call girls in Jalandhar ☎️8264406502☎️ Call Girl service in Jalandhar☎...
 
Top 10 Moisturising Cream Brands In India - Stelon Biotech
Top 10 Moisturising Cream Brands In India - Stelon BiotechTop 10 Moisturising Cream Brands In India - Stelon Biotech
Top 10 Moisturising Cream Brands In India - Stelon Biotech
 
Zirakpur Call Girls Service ❤️🍑 7837612180 👄🫦Independent Escort Service Zirakpur
Zirakpur Call Girls Service ❤️🍑 7837612180 👄🫦Independent Escort Service ZirakpurZirakpur Call Girls Service ❤️🍑 7837612180 👄🫦Independent Escort Service Zirakpur
Zirakpur Call Girls Service ❤️🍑 7837612180 👄🫦Independent Escort Service Zirakpur
 

Page Caching Resurrected

  • 1. Page Caching Resurrected Ben Sco eld – Viget Labs
  • 2. Page Caching Resurrected: A Fairy Tale Ben Sco eld – Viget Labs
  • 3.
  • 7.
  • 8.
  • 9. class PigsController caches_page :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_page :action => :show end end
  • 10. class PigsController caches_page :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_page :action => :show end end
  • 11. class PigsController caches_page :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_page :action => :show end end
  • 12. standard 1 page 3000 requests per second
  • 15.
  • 16.
  • 17. class PigsController require_login :show caches_action :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_action :action => :show end end
  • 18. class PigsController require_login :show caches_action :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_action :action => :show end end
  • 19. class PigsController require_login :show caches_action :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_action :action => :show end end
  • 20. standard 1 action 500 page 3000 requests per second
  • 23.
  • 24.
  • 25. <% cache(:key => 'index:piglist') do %> <ul id=quot;pig-listquot;> <% @pigs.each do |pig| %> <li> <%= image_tag pig.house.photo %> <%= h pig.name %> </li> <% end %> </ul> <% end %>
  • 26. <% cache(:key => 'index:piglist') do %> <ul id=quot;pig-listquot;> <% @pigs.each do |pig| %> <li> <%= image_tag pig.house.photo %> <%= h pig.name %> </li> <% end %> </ul> <% end %>
  • 27. class PigsController # ... def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_fragment :key => 'index:piglist' end end
  • 28. class PigsController # ... def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_fragment :key => 'index:piglist' end end
  • 29. standard 1 fragment 20 action 500 page 3000 requests per second
  • 34. class BigBadWolf def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/threaten/ [ 200, {quot;Content-Typequot; = quot;text/htmlquot;}, quot;Little pig, little pig, let me in!quot; ] else [ 404, {quot;Content-Typequot; = quot;text/htmlquot;}, quot;Not Foundquot; ] end end end
  • 36. AJAX
  • 37. so...
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46. ul id=quot;logged-out-navquot; class=quot;usernavquot; style=quot;display:nonequot; li class=quot;first sign-out-linkquot; a class=quot;utility-linkquot; href=quot;#quot; id=quot;login-linkquot; onclick=quot;Login.show($('top-login-form')); return false;quot;Login/a /li li class=quot;signin-border-leftquot; a href=quot;/users/forgot_passwordquot; class=quot;utility-linkquot;Forgot Password?/a /li li class=quot;signin-border-leftquot; a href=quot;/signupquot; class=quot;utility-linkquot;Sign Up/a /li /ul
  • 47. div id=quot;top-login-formquot; class=quot;usernav login-formquot; style=quot;display:nonequot; form action=quot;https://secure.hulu.com/account/authenticatequot; method=quot;getquot; name=quot;login-formquot; onsubmit=quot;Login.submit(this); return false;quot; span class=quot;login-statusquot;/span input id=quot;loginquot; class=quot;active loginquot; type=quot;textquot; style=quot;display: none;quot; name=quot;usernamequot;/ input id=quot;passwordquot; class=quot;active passwordquot; type=quot;passwordquot; style=quot;display: none;quot; name=quot;passwordquot;/ input class=quot;inactive dummy loginquot; type=quot;textquot; value=quot;usernamequot; name=quot;dummy_loginquot; / input class=quot;inactive dummyquot; type=quot;textquot; value=quot;passwordquot; name=quot;dummy_passwordquot; / input alt=quot;Loginquot; class=quot;login-submitquot; src=quot;http://static.hulu.com/images/btn-signin-small.gif?1237361096quot; style=quot;width: 39px; height: 20;quot; type=quot;imagequot; / a href=quot;#quot;img alt=quot;Cancelquot; border=quot;0quot; class=quot;hover-mequot; height=quot;20quot; id=quot;btn-x.gif123741536309506quot; onclick=quot;Login.cancel();return falsequot; src=quot;http://static.hulu.com/images/btn-x.gif?1237361096quot; width=quot;18quot; //a /form a href=quot;/signupquot; class=quot;utility-linkquot;Sign Up/a /div
  • 48. ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot; li id=quot;welcome-usernamequot; class=quot;firstquot; Welcome /li li a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a /li li a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a /li li class=quot;sign-out-linkquot; a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a /li /ul
  • 49. noscript ul class=quot;nojs usernavquot; li Please a href=quot;/support/quot;enable javascript/a to log in. /li /ul /noscript
  • 50. script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]*//script
  • 51. ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot; li id=quot;welcome-usernamequot; class=quot;firstquot; Welcome /li li a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a /li li a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a /li li class=quot;sign-out-linkquot; a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a /li /ul
  • 52. ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot; li id=quot;welcome-usernamequot; class=quot;firstquot; Welcome /li li a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a /li li a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a /li li class=quot;sign-out-linkquot; a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a /li /ul
  • 53.
  • 54. hulu is insane don’t do it like they do
  • 55. script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]*//script
  • 56. script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]*//script
  • 58.
  • 59.
  • 60.
  • 62. class ItemsController ApplicationController def index @user = User.find_by_login(params[:user]) @items = Item.released_on(params[:date]) end end
  • 63. class Item ActiveRecord::Base has_many :pulls, :dependent = :destroy named_scope :released_on, lambda { |date| date ||= Item.maximum(:released_on) {:conditions = {:released_on = date}, :order = 'name ASC'} } def pulled_by?(user) x = user.nil? ? false : !self.pulls.by_user(user.id).empty? end end
  • 64. h1Releases/h1 ul % @items.each do |item| % % content_tag_for :li, item do % %= image_tag 'cover.png', :alt = h(item.name), :class = 'cover' % %= image_tag('badge.png', :alt = 'pulling',:class = 'badge') if item.pulled_by?(@user) % p%= h item.name %/p % end % % end % /ul
  • 65.
  • 67. class ItemsController ApplicationController caches_page :index def index @items = Item.released_on(params[:date]).all end end
  • 68. require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless defined?(Rails) class PullList def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/pulls/ date = '2008-11-05' user = '1' [ 200, {quot;Content-Typequot; = quot;application/javascriptquot;}, [Pull.by_user(user).for_date(date).map {|i| i.item_id}.to_json]] else [404, {quot;Content-Typequot; = quot;text/htmlquot;}, [quot;Not Foundquot;]] end end end
  • 69. class Pull ActiveRecord::Base belongs_to :user belongs_to :item named_scope :by_user, lambda { |user_id| {:conditions = {:user_id = user_id}} } named_scope :for_date, lambda { |date| {:include = :item, :conditions = {:items = {:released_on = date}}} } end
  • 70. $(document).ready(function() { $.getJSON('/pulls', function(data) { $.each(data, function() { $('#item_'+this).addClass('pulled'); }); }); });
  • 73. standard 0.617 hybrid 0.039 0.096 content load time
  • 74. hybrid approach - version 2
  • 75. class SessionsController ApplicationController def new; end def create # ... session[:pulls] = @user.pulls.map {|i| i.item_id} redirect_to items_path end end
  • 76. require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless defined?(Rails) class PullList def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/pulls/ date = '2008-11-05' user = '1' [ 200, {quot;Content-Typequot; = quot;application/javascriptquot;}, [env['rack.session'][:pulls].to_json] ] else [404, {quot;Content-Typequot; = quot;text/htmlquot;}, [quot;Not Foundquot;]] end end end
  • 78. standard 0.617 hybrid 0.039 0.096 hybrid v2 0.043 0.023 content load time
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86. when not to use it
  • 87.
  • 90. noscript ul class=quot;nojs usernavquot; li Please a href=quot;/support/quot;enable javascript/a to log in. /li /ul /noscript
  • 91. Thank You ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/bsco eld

Editor's Notes

  1. super simple to use, but results in PUBLIC content
  2. super simple to use, but results in PUBLIC content
  3. more framework-specific; solves auth-protected pages, etc. - cached content is not publicly available
  4. more framework-specific; solves auth-protected pages, etc. - cached content is not publicly available
  5. caches only specific parts of the page, which are not publically available
  6. expiration of each fragment, individually
  7. 10 minutes
  8. 15 minutes
  9. 22 minutes
  10. 26 minutes
  11. 135ms for hybrid, which is 21% of the standard lame tests I employed showed the same or greater effect
  12. 26 minutes
  13. 66ms for hybrid v2, 10.6% of standard and 48% of hybrid
  14. 34 minutes