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

Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxRemote DBA Services
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...Zilliz
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...apidays
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistandanishmna97
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Bhuvaneswari Subramani
 

Recently uploaded (20)

Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 

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