SlideShare a Scribd company logo
1 of 77
Page Caching Resurrected:

                   Ben Sco eld – Viget Labs




Sunday, March 22, 2009
Page Caching Resurrected:
                   A Fairy Tale
                   Ben Sco eld – Viget Labs




Sunday, March 22, 2009
I’m a Rails guy


Sunday, March 22, 2009
and this is a Rails talk


Sunday, March 22, 2009
but this isn’t just for Rails


Sunday, March 22, 2009
the story


Sunday, March 22, 2009
Sunday, March 22, 2009
page caching



Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
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




Sunday, March 22, 2009
Standard        1




                Page     3000




                                requests per second




Sunday, March 22, 2009
public

                         dynamic
                         content

Sunday, March 22, 2009
action caching


Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
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




Sunday, March 22, 2009
Standard        1



              Action     500



                Page     3000




                                requests per second




Sunday, March 22, 2009
dynamic
                         content


Sunday, March 22, 2009
fragment caching

Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
<% 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 %>




Sunday, March 22, 2009
class PigsController
                 # ...

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

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




Sunday, March 22, 2009
Standard        1


         Fragment        20


              Action     500


                Page     3000




                                requests per second




Sunday, March 22, 2009
efficiency


Sunday, March 22, 2009
the idea


Sunday, March 22, 2009
Rails 2.3

Sunday, March 22, 2009
hello, metal


Sunday, March 22, 2009
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




Sunday, March 22, 2009
high-performance endpoints


Sunday, March 22, 2009
AJAX


Sunday, March 22, 2009
so...


Sunday, March 22, 2009
javascript

Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
<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>




Sunday, March 22, 2009
<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-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>




Sunday, March 22, 2009
<noscript>
     <ul class=quot;nojs usernavquot;>
      <li>
       Please <a href=quot;/support/quot;>enable javascript</a> to log in.
      </li>
     </ul>
    </noscript>

    <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>




Sunday, March 22, 2009
<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-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>




Sunday, March 22, 2009
Sunday, March 22, 2009
hulu is insane
                          don’t do it like they do




Sunday, March 22, 2009
<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>




Sunday, March 22, 2009
<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>




Sunday, March 22, 2009
the* right way


                               *a
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
the standard approach




Sunday, March 22, 2009
class ItemsController < ApplicationController
      def index
        @user = User.find_by_login(params[:user])
        @items = Item.released_on(params[:date])
      end
     end




Sunday, March 22, 2009
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




Sunday, March 22, 2009
<h1>Releases</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>




Sunday, March 22, 2009
the hybrid approach




Sunday, March 22, 2009
class ItemsController < ApplicationController
      caches_page :index

      def index
       @items = Item.released_on(params[:date]).all
      end
     end




Sunday, March 22, 2009
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




Sunday, March 22, 2009
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




Sunday, March 22, 2009
$(document).ready(function() {
       $.getJSON('/pulls', function(data) {
         $.each(data, function() {
           $('#item_'+this).addClass('pulled');
         });
       });
     });




Sunday, March 22, 2009
the payoff


Sunday, March 22, 2009
Sunday, March 22, 2009
standard


Sunday, March 22, 2009
hybrid


Sunday, March 22, 2009
Standard        0.617




              Hybrid     0.039 0.096




                                       content load time




Sunday, March 22, 2009
when to use it




Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
Sunday, March 22, 2009
no shirt, no javascript, no service




Sunday, March 22, 2009
Thank You
      ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/speakers/44
Sunday, March 22, 2009

More Related Content

Similar to Page Caching Resurrected: A Fairy Tale

Page Caching Resurrected
Page Caching ResurrectedPage Caching Resurrected
Page Caching ResurrectedBen Scofield
 
Background Processing in Ruby on Rails
Background Processing in Ruby on RailsBackground Processing in Ruby on Rails
Background Processing in Ruby on Railsrobmack
 
Latinoware Rails 2009
Latinoware Rails 2009Latinoware Rails 2009
Latinoware Rails 2009Fabio Akita
 
An Introduction To jQuery
An Introduction To jQueryAn Introduction To jQuery
An Introduction To jQueryAndy Gibson
 
IT Depends: Custom vs Packaged Software
IT Depends: Custom vs Packaged SoftwareIT Depends: Custom vs Packaged Software
IT Depends: Custom vs Packaged Software★ Selcuk Atli
 
Ecossistema Rails Campus Party 09
Ecossistema Rails   Campus Party 09Ecossistema Rails   Campus Party 09
Ecossistema Rails Campus Party 09Fabio Akita
 
Hacking Movable Type Training - Day 2
Hacking Movable Type Training - Day 2Hacking Movable Type Training - Day 2
Hacking Movable Type Training - Day 2Byrne Reese
 
Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)Sam Livingston-Gray
 
Google Analytics and Sungard HE Luminis
Google Analytics and Sungard HE LuminisGoogle Analytics and Sungard HE Luminis
Google Analytics and Sungard HE LuminisDavid Simpson
 
Adventurous Merb
Adventurous MerbAdventurous Merb
Adventurous MerbMatt Todd
 
Semcomp de São Carlos
Semcomp de São CarlosSemcomp de São Carlos
Semcomp de São CarlosFabio Akita
 
Javascript: Ajax & DOM Manipulation v1.2
Javascript: Ajax & DOM Manipulation v1.2Javascript: Ajax & DOM Manipulation v1.2
Javascript: Ajax & DOM Manipulation v1.2borkweb
 
Front end performance (RailsWayCon 2009 short talk)
Front end performance (RailsWayCon 2009 short talk)Front end performance (RailsWayCon 2009 short talk)
Front end performance (RailsWayCon 2009 short talk)Ralph von der Heyden
 
シックス・アパート・フレームワーク
シックス・アパート・フレームワークシックス・アパート・フレームワーク
シックス・アパート・フレームワークTakatsugu Shigeta
 
Lightweight Webservices with Sinatra and RestClient
Lightweight Webservices with Sinatra and RestClientLightweight Webservices with Sinatra and RestClient
Lightweight Webservices with Sinatra and RestClientAdam Wiggins
 
Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On RailsWen-Tien Chang
 
jQuery Internals + Cool Stuff
jQuery Internals + Cool StuffjQuery Internals + Cool Stuff
jQuery Internals + Cool Stuffjeresig
 

Similar to Page Caching Resurrected: A Fairy Tale (20)

Page Caching Resurrected
Page Caching ResurrectedPage Caching Resurrected
Page Caching Resurrected
 
Background Processing in Ruby on Rails
Background Processing in Ruby on RailsBackground Processing in Ruby on Rails
Background Processing in Ruby on Rails
 
Enecomp 2009
Enecomp 2009Enecomp 2009
Enecomp 2009
 
Latinoware Rails 2009
Latinoware Rails 2009Latinoware Rails 2009
Latinoware Rails 2009
 
An Introduction To jQuery
An Introduction To jQueryAn Introduction To jQuery
An Introduction To jQuery
 
IT Depends: Custom vs Packaged Software
IT Depends: Custom vs Packaged SoftwareIT Depends: Custom vs Packaged Software
IT Depends: Custom vs Packaged Software
 
Ecossistema Rails Campus Party 09
Ecossistema Rails   Campus Party 09Ecossistema Rails   Campus Party 09
Ecossistema Rails Campus Party 09
 
Hacking Movable Type Training - Day 2
Hacking Movable Type Training - Day 2Hacking Movable Type Training - Day 2
Hacking Movable Type Training - Day 2
 
Ajax
AjaxAjax
Ajax
 
Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)
 
Google Analytics and Sungard HE Luminis
Google Analytics and Sungard HE LuminisGoogle Analytics and Sungard HE Luminis
Google Analytics and Sungard HE Luminis
 
Adventurous Merb
Adventurous MerbAdventurous Merb
Adventurous Merb
 
Semcomp de São Carlos
Semcomp de São CarlosSemcomp de São Carlos
Semcomp de São Carlos
 
Debugging Django
Debugging DjangoDebugging Django
Debugging Django
 
Javascript: Ajax & DOM Manipulation v1.2
Javascript: Ajax & DOM Manipulation v1.2Javascript: Ajax & DOM Manipulation v1.2
Javascript: Ajax & DOM Manipulation v1.2
 
Front end performance (RailsWayCon 2009 short talk)
Front end performance (RailsWayCon 2009 short talk)Front end performance (RailsWayCon 2009 short talk)
Front end performance (RailsWayCon 2009 short talk)
 
シックス・アパート・フレームワーク
シックス・アパート・フレームワークシックス・アパート・フレームワーク
シックス・アパート・フレームワーク
 
Lightweight Webservices with Sinatra and RestClient
Lightweight Webservices with Sinatra and RestClientLightweight Webservices with Sinatra and RestClient
Lightweight Webservices with Sinatra and RestClient
 
Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On Rails
 
jQuery Internals + Cool Stuff
jQuery Internals + Cool StuffjQuery Internals + Cool Stuff
jQuery Internals + Cool Stuff
 

More from Ben Scofield

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 StepsBen Scofield
 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUGBen Scofield
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers StealBen Scofield
 
Open Source: A Call to Arms
Open Source: A Call to ArmsOpen Source: A Call to Arms
Open Source: A Call to ArmsBen Scofield
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud CastlesBen Scofield
 
Intentionality: Choice and Mastery
Intentionality: Choice and MasteryIntentionality: Choice and Mastery
Intentionality: Choice and MasteryBen Scofield
 
Mastery or Mediocrity
Mastery or MediocrityMastery or Mediocrity
Mastery or MediocrityBen Scofield
 
With a Mighty Hammer
With a Mighty HammerWith a Mighty Hammer
With a Mighty HammerBen Scofield
 
Mind Control - DevNation Atlanta
Mind Control - DevNation AtlantaMind Control - DevNation Atlanta
Mind Control - DevNation AtlantaBen Scofield
 
Understanding Mastery
Understanding MasteryUnderstanding Mastery
Understanding MasteryBen Scofield
 
Mind Control: Psychology for the Web
Mind Control: Psychology for the WebMind Control: Psychology for the Web
Mind Control: Psychology for the WebBen Scofield
 
The State of NoSQL
The State of NoSQLThe State of NoSQL
The State of NoSQLBen Scofield
 
NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010Ben Scofield
 
NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)Ben Scofield
 
Charlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardCharlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardBen Scofield
 
WindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardWindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardBen Scofield
 
"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative DatabasesBen Scofield
 
Mind Control on the Web
Mind Control on the WebMind Control on the Web
Mind Control on the WebBen Scofield
 
How the Geeks Inherited the Earth
How the Geeks Inherited the EarthHow the Geeks Inherited the Earth
How the Geeks Inherited the EarthBen Scofield
 

More from Ben Scofield (20)

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
 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUG
 
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
 
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
 
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

Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsSnow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsHyundai Motor Group
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAndikSusilo4
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraDeakin University
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxnull - The Open Security Community
 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Hyundai Motor Group
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 

Recently uploaded (20)

Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsSnow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & Application
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning era
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 

Page Caching Resurrected: A Fairy Tale

  • 1. Page Caching Resurrected: Ben Sco eld – Viget Labs Sunday, March 22, 2009
  • 2. Page Caching Resurrected: A Fairy Tale Ben Sco eld – Viget Labs Sunday, March 22, 2009
  • 3. I’m a Rails guy Sunday, March 22, 2009
  • 4. and this is a Rails talk Sunday, March 22, 2009
  • 5. but this isn’t just for Rails Sunday, March 22, 2009
  • 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 Sunday, March 22, 2009
  • 12. Standard 1 Page 3000 requests per second Sunday, March 22, 2009
  • 13. public dynamic content Sunday, March 22, 2009
  • 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 Sunday, March 22, 2009
  • 18. Standard 1 Action 500 Page 3000 requests per second Sunday, March 22, 2009
  • 19. dynamic content Sunday, March 22, 2009
  • 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 %> Sunday, March 22, 2009
  • 26. class PigsController # ... def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_fragment :key => 'index:piglist' end end Sunday, March 22, 2009
  • 27. Standard 1 Fragment 20 Action 500 Page 3000 requests per second Sunday, March 22, 2009
  • 32. 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 Sunday, March 22, 2009
  • 44. <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> Sunday, March 22, 2009
  • 45. <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-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> Sunday, March 22, 2009
  • 46. <noscript> <ul class=quot;nojs usernavquot;> <li> Please <a href=quot;/support/quot;>enable javascript</a> to log in. </li> </ul> </noscript> <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> Sunday, March 22, 2009
  • 47. <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-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> Sunday, March 22, 2009
  • 49. hulu is insane don’t do it like they do Sunday, March 22, 2009
  • 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> Sunday, March 22, 2009
  • 51. <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> Sunday, March 22, 2009
  • 52. the* right way *a Sunday, March 22, 2009
  • 56. class ItemsController < ApplicationController def index @user = User.find_by_login(params[:user]) @items = Item.released_on(params[:date]) end end Sunday, March 22, 2009
  • 57. 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 Sunday, March 22, 2009
  • 58. <h1>Releases</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> Sunday, March 22, 2009
  • 59. the hybrid approach Sunday, March 22, 2009
  • 60. class ItemsController < ApplicationController caches_page :index def index @items = Item.released_on(params[:date]).all end end Sunday, March 22, 2009
  • 61. 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 Sunday, March 22, 2009
  • 62. 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 Sunday, March 22, 2009
  • 63. $(document).ready(function() { $.getJSON('/pulls', function(data) { $.each(data, function() { $('#item_'+this).addClass('pulled'); }); }); }); Sunday, March 22, 2009
  • 68. Standard 0.617 Hybrid 0.039 0.096 content load time Sunday, March 22, 2009
  • 69. when to use it Sunday, March 22, 2009
  • 76. no shirt, no javascript, no service Sunday, March 22, 2009
  • 77. Thank You ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/speakers/44 Sunday, March 22, 2009

Editor's Notes

  1. 3 minutes
  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. caches only specific parts of the page, which are not publically available
  5. expiration of each fragment, individually
  6. 10 minutes
  7. 15 minutes
  8. 22 minutes
  9. 26 minutes
  10. 32 minutes
  11. 135ms for hybrid, which is 21% of the standard lame tests I employed showed the same or greater effect
  12. 34 minutes