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
 
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
 
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
 
Intro to jQuery
Intro to jQueryIntro to jQuery
Intro to jQuery
 

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

Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
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
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 

Recently uploaded (20)

Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
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
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
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
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 

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