<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>Hungry Machine</title>
	
	<link>http://blog.hungrymachine.com</link>
	<description>The guys behind LivingSocial</description>
	<lastBuildDate>Wed, 08 Jul 2009 15:56:08 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/hungrymachine" type="application/rss+xml" /><item>
		<title>JRuby “include?” 2x faster than 1.8.6?</title>
		<link>http://blog.hungrymachine.com/2009/07/07/jruby-include-2x-faster-than-1-8-6/</link>
		<comments>http://blog.hungrymachine.com/2009/07/07/jruby-include-2x-faster-than-1-8-6/#comments</comments>
		<pubDate>Tue, 07 Jul 2009 17:54:08 +0000</pubDate>
		<dc:creator>aaron</dc:creator>
				<category><![CDATA[performance]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://blog.hungrymachine.com/?p=2920</guid>
		<description><![CDATA[Its been a few months since I&#8217;ve looked at JRuby and 1.8.6  can be annoying slow at simple things. So this morning I took another look at Ruby1.9 and JRuby.
See gist below:

6.587s (1.8.6) vs. 5.687s (1.9) vs. 3.556s (JRuby 1.4)&#8230; and that&#8217;s just the include method. JRuby is almost 2x 1.8.6 without any optimizations.  I&#8217;ve read [...]]]></description>
			<content:encoded><![CDATA[<p>Its been a few months since I&#8217;ve looked at JRuby and 1.8.6  can be annoying slow at simple things. So this morning I took another look at Ruby1.9 and JRuby.</p>
<p>See gist below:<br />
<script src="http://gist.github.com/142233.js"></script></p>
<p>6.587s (1.8.6) vs. 5.687s (1.9) vs. 3.556s (JRuby 1.4)&#8230; and that&#8217;s just the include method. JRuby is almost 2x 1.8.6 without any optimizations.  I&#8217;ve read this this <a href="http://blog.headius.com/2009/04/how-jruby-makes-ruby-fast.html">awesome article</a> about JRuby perf optimizations, but its unclear which flags are safe to run in a production environment beyond &#8216;&#8211;server&#8217;, which didn&#8217;t seem to impact local testing of a handful of iterations.</p>
<p>Does anyone have Rails benchmarks running nightly comparing 1.8.6 against jruby?  I guess thats a more comprehensive test.</p>
<p>UPDATE:  Eddie guessed PHP was much faster&#8230;  Apparently not.<br />
<script src="http://gist.github.com/142262.js"></script></p>
<p>UPDATE 2: Warren suggested a different method other than include, that would work. (a &#038; [i]).empty?<br />
<script src="http://gist.github.com/142269.js"></script><br />
Interesting to see it much faster on 1.8.6, consistent on JRuby, and slower on 1.9    </p>
<p>UPDATE 3 : Responses to comments from dmilith:  Sorry.The original gist had version numbers, if you look at its history. I put them back.  I do mention &#8211;server above, and even adding warmup to the script, it doesnt appear to impact numbers as all.  But for it to be warmed up, you&#8217;d have to run the benchmark 10k times? Whats an acceptable warmup period?  Also,  &#8211;fast seems strange to me.  Didnt help the numbers as well.</p>
<p>I hate when people say uBenchmarks suck.  The ruby lang specs should include a suite of these types benchmarks as well.  Its important to keep tabs on them to help find route cause when macro performance suites improve/degrade over time.</p>
<img src="http://feeds.feedburner.com/~r/hungrymachine/~4/fQyJKD7__nw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.hungrymachine.com/2009/07/07/jruby-include-2x-faster-than-1-8-6/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>LivingSocial has EXPLODED! We’re hiring!</title>
		<link>http://blog.hungrymachine.com/2009/06/11/livingsocial-has-exploded-we-are-hiring/</link>
		<comments>http://blog.hungrymachine.com/2009/06/11/livingsocial-has-exploded-we-are-hiring/#comments</comments>
		<pubDate>Thu, 11 Jun 2009 21:54:25 +0000</pubDate>
		<dc:creator>aaron</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://blog.hungrymachine.com/?p=2859</guid>
		<description><![CDATA[We&#8217;re Hiring!
LivingSocial is a social cataloging and discovery platform which connects you with the things you care about.  If Google mapped all the documents on the web, and Facebook has mapped the social graph, LivingSocial maps people to the things they care about.
Located in Washington, DC and backed by Grotech Ventures and Steve &#38; [...]]]></description>
			<content:encoded><![CDATA[<h3>We&#8217;re Hiring!</h3>
<p><a href="http://www.livingsocial.com/">LivingSocial</a> is a social cataloging and discovery platform which connects you with the things you care about.  If Google mapped all the documents on the web, and Facebook has mapped the social graph, LivingSocial maps people to the things they care about.</p>
<p>Located in Washington, DC and backed by <a href="http://grotechventures.com/">Grotech Ventures</a> and <a href="http://www.revolution.com/our-team/bio-steve-case.aspx">Steve &amp; Jean Case</a>, LivingSocial has 50M users and over 1B user preferences, with hundreds of millions of page views per month. We&#8217;re currently the <a href="http://apps.facebook.com/livingsocial/">largest application</a> on Facebook. We&#8217;re building the largest database of people and things on the planet.</p>
<p>From the people we hire to the products we build, to how we take care of our employees, LivingSocial aims to be a place people loving coming to work every day. Our technical team is small, but we believe less of the right people can do a lot more. Millions of people use our products every day and we&#8217;re deeply committed to building products they love.  Contact us at: <strong>jobs@livingsocial.com</strong></p>
<h3>Who we&#8217;re looking for:</h3>
<h4>Web Developers:</h4>
<ul style="text-align: left;">
<li>Proven ability to build and launch web applications you are proud of and people love. Send us links!</li>
<li>You are self motivated and creative.</li>
<li>You take extreme pride in your work.</li>
<li>You are pragmatic. You simply get things done.</li>
<li>At least 3 years of web development experience, frontend and/or backend.</li>
<li>Qualified candidates should have Ruby/Rails experience, but not required.</li>
</ul>
<h4>Lead Data Warehouse Engineer:</h4>
<ul style="text-align: left;">
<li>Real world experience with billions of pieces of data.</li>
<li>Strong design/admin experience with relational DB&#8217;s, esp. MySQL/Postgres/Oracle/Teradata/Hadoop/MapReduce.</li>
<li>Expert in Ruby/Java/Python/C++ development and debugging on a Linux platform.</li>
<li>Analytical and meticulous in addressing performance, scalability and efficiency of large data warehouses.</li>
</ul>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">Lead Analytics Engineer</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">An expert in developing scalable recommendation engines and continuously improving their quality.</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">Expertise in clustering and classification techniques (SVM, NN, Boosting Methods, RF, etc.)</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">Expertise in multivariate analysis, hypothesis testing, simulation, machine learning, large-scale data mining, statistical mining, times series analysis.</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">Previously built a recommendation engine to drive online consumer recommendations</div>
<h4>Lead Analytics Engineer:</h4>
<ul>
<li>An expert in developing scalable recommendation engines and continuously improving their quality.</li>
<li>Expertise in clustering and classification techniques (SVM, NN, Boosting Methods, RF, etc.)</li>
<li>Expertise in multivariate analysis, hypothesis testing, simulation, machine learning, large-scale data mining, statistical mining, times series analysis.</li>
<li>Previously built a recommendation engine to drive online consumer recommendations</li>
</ul>
<h3><strong>We&#8217;d also like to get to know you better.</strong></h3>
<p>When you reach out, answer some of the questions below.</p>
<ul>
<li>What are your 5 favorite websites on the internet and why?</li>
<li>iPhone or Palm Pre? Why?</li>
<li>Name five things you don&#8217;t leave the house without.</li>
<li>If you were recommending your favorite book/movie/beer/album/etc to us, what would you say?</li>
</ul>
<p style="text-align: center;"><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="300" height="450" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="flashvars" value="offsite=true&amp;lang=en-us&amp;page_show_url=%2Fphotos%2Flivingsocial%2Fsets%2F72157619607165618%2Fshow%2F&amp;page_show_back_url=%2Fphotos%2Flivingsocial%2Fsets%2F72157619607165618%2F&amp;set_id=72157619607165618&amp;jump_to=" /><param name="allowFullScreen" value="true" /><param name="src" value="http://www.flickr.com/apps/slideshow/show.swf?v=71649" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="300" height="450" src="http://www.flickr.com/apps/slideshow/show.swf?v=71649" allowfullscreen="true" flashvars="offsite=true&amp;lang=en-us&amp;page_show_url=%2Fphotos%2Flivingsocial%2Fsets%2F72157619607165618%2Fshow%2F&amp;page_show_back_url=%2Fphotos%2Flivingsocial%2Fsets%2F72157619607165618%2F&amp;set_id=72157619607165618&amp;jump_to="></embed></object></p>
<p style="text-align: center;">Contact us: <strong>jobs@livingsocial.com</strong></p>
<p style="text-align: left;"><strong><br />
</strong></p>
<img src="http://feeds.feedburner.com/~r/hungrymachine/~4/pHltHqtNPtA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.hungrymachine.com/2009/06/11/livingsocial-has-exploded-we-are-hiring/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby Scoping Bug?</title>
		<link>http://blog.hungrymachine.com/2009/01/28/ruby-scoping-bug/</link>
		<comments>http://blog.hungrymachine.com/2009/01/28/ruby-scoping-bug/#comments</comments>
		<pubDate>Wed, 28 Jan 2009 19:18:48 +0000</pubDate>
		<dc:creator>warren</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.hungrymachine.com/?p=2852</guid>
		<description><![CDATA[class Foo
  def title
    "Oh hai."
  end

  def buggy
    puts title

    if false
      title = 'Oh noes!'
    end

    puts title
  end
end

Foo.new.buggy
This code outputs:
Oh hai.
nil
Isn&#8217;t it odd that the variable being created [...]]]></description>
			<content:encoded><![CDATA[<pre>class Foo
  def title
    "Oh hai."
  end

  def buggy
    puts title

    if false
      title = 'Oh noes!'
    end

    puts title
  end
end

Foo.new.buggy</pre>
<p>This code outputs:</p>
<pre>Oh hai.
nil</pre>
<p>Isn&#8217;t it odd that the variable being created in an if-false block is still being created and set to nil?  Hopefully this is fixed in Ruby 1.9.</p>
<img src="http://feeds.feedburner.com/~r/hungrymachine/~4/P6grkHkMyZI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.hungrymachine.com/2009/01/28/ruby-scoping-bug/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Merb routing in Rails – Today!</title>
		<link>http://blog.hungrymachine.com/2008/12/29/merb-routing-in-rails/</link>
		<comments>http://blog.hungrymachine.com/2008/12/29/merb-routing-in-rails/#comments</comments>
		<pubDate>Mon, 29 Dec 2008 23:01:34 +0000</pubDate>
		<dc:creator>warren</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://blog.hungrymachine.com/?p=2816</guid>
		<description><![CDATA[We&#8217;ve been hearing great things about Merb routing so a few weeks ago, we wanted to see if we could get it working in a Rails application as a proof of concept.  The goal of this project was to use the Merb routing engine along with router.rb and without touching any of our existing Rails [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve been hearing great things about Merb routing so a few weeks ago, we wanted to see if we could get it working in a Rails application as a proof of concept.  The goal of this project was to use the Merb routing engine along with router.rb and without touching any of our existing Rails application (i.e. anything in app/*).   Pre-existing URL route recognition needed to continue to work and all named routes and url_for logic needed to generate the same URLs as before.</p>
<p>With the <a href="http://weblog.rubyonrails.org/2008/12/23/merb-gets-merged-into-rails-3" target="_blank">announcement that Merb and Rails are merging</a>, we figured that it&#8217;d be a great time to share a little bit of what we learned.</p>
<h3>Background</h3>
<ul>
<li>We&#8217;re running Rails 2.2.2.</li>
<li>When we started messing with routes, we had 2500 generated routes (i.e. &#8220;rake routes | wc -l&#8221;).  After Aaron&#8217;s <a href="http://rails.lighthouseapp.com/projects/8994/tickets/1359-add-optional-format-argument-to-named-routes" target="_blank">formatted routes patch</a>, we had 1250.  We currently have over 1500.</li>
<li>Routing accounted for around 4 seconds out of 6 for ./script/console and mongrel_rails to start up.</li>
<li>Each mongrel_rails process was running at a minimum of 250mb in production.</li>
</ul>
<h3>Step 1: compiling</h3>
<p><em>Compiling is the first part of routing and involves loading an application&#8217;s routes.rb or router.rb and storing it in some way that allows for generation and recognition.</em></p>
<p>The merb_routing plugin contains a subset of merb-core&#8230; just the classes related to routes.  It shouldn&#8217;t be a surprise that these classes assume they are running in a Merb environment and not a Rails environment.  To successfully load these merb routing classes without drastically modifying the source, we wrote two small compatibility layers (mini-merb and mini-extlib) that provide some basic functionality that Merb and ExtLib provide (i.e. Merb.logger, Merb.root, etc).  This enabled us to successfully load the Merb::Router classes in our environment without any errors.</p>
<p>We then rewrote our routes.rb by hand using router.rb syntax.  We had to modify Merb routing slightly because we were getting &#8220;memory exhausted&#8221; compile errors.  It turned out that Merb routing uses a single if/elsif structure to recognize routes and due to our large number of routes, we hit a ruby quirk where you can&#8217;t have more than 2498 branches of logic in a single if-elsif statement.</p>
<blockquote><p><code>irb(main):001:0&gt; eval("if 1; #{"elsif 1;" * 2498} end")<br />
=&gt; nil<br />
irb(main):002:0&gt; eval("if 1; #{"elsif 1;" * 2499} end")<br />
SyntaxError: (eval):1:in `irb_binding': compile error<br />
(eval):1: memory exhausted</code></p></blockquote>
<p>The quick fix was using many single if statement with a return inside rather than one giant if-elsif.    After a few hooks into ActionController::Routing we had our environment using Merb/router.rb instead of Rails/routes.rb.</p>
<p>We had to make a few other minor changes to Merb routing to be compatible with rails:</p>
<ul>
<li>added support for { :method =&gt; :any } in routing conditions</li>
<li>added support for BLAH_index as a named route for singular resources (Rails creates a named route called &#8220;blog_index&#8221; instead of just &#8220;blog&#8221; for singular resources)</li>
</ul>
<p>Lastly, we wrote a rake task that overrides the default &#8220;rake routes&#8221; to pull from Merb routes instead of Rails routes.  At this point, we had the routes loaded and could see the objects in script/console.</p>
<h3>Step 2: recognizing</h3>
<p><em>Recognition is the second part of routing and happens at the beginning of every request.  It translates a URL into various parameters and figures out which controller/action to invoke for that request.</em></p>
<p>Once we had router.rb working correctly, route recognition and parameter loading was surprisingly easy to wire in.</p>
<h3>Step 3: generating</h3>
<p><em>Generation is the third part of routing and translates structured options into a URL string.  This happens every time you use url_for, a named route helper or redirect_to.</em></p>
<p>Generation was the trickiest part of this project and had the most edge cases.  Philosophically speaking, Merb and Rails route generation are very different.  Rails gives you named routes as helpers (person_path, person_url, etc) that you can use as well as a url_for() method which will search through all of the routes and find the best route given the options you provide.  Merb on the other hand provides a single method, url(), which all generation goes through.  If you don&#8217;t explicitly provide a named route, url() will use the default route (i.e. :controller/:action/:id) rather than looking for the &#8220;best route&#8221;.</p>
<p>Getting the named routes to work was pretty easy and only required a single method_missing catch-all for ActionController::Base and ActionView::Base.  Using a simple regexp, if the requested method ends in _url or _path, it uses Merb::Router#url and passes in the named route.</p>
<p>There was a bit of trickery involved in getting the path vs. url as well as the  :only_path stuff working correctly, but overall not too hard.</p>
<p>The last tricky piece was returning the best route instead of the default route when no named route was provided.  This is accomplished by looping through all of the available routes and determining which of the routes satisfies the most options passed in.  With 1500 routes, this turned out to be a bit slow, so some optimization ideas were borrowed from Rails and a cache is maintained of available routes given a controller/action.</p>
<h3>Conclusion</h3>
<p>We&#8217;ve been using this plugin successfully in production for the last month.  Our environment startup time as well as our memory overhead were both reduced drastically as soon as we put it in to production. We started this development when Rails 2.1 was the latest stable release and benchmarks against Rails 2.1 put Merb routing way ahead in just about every metric we tested.</p>
<p>The routing in Rails 2.2 was sped up substantially and is now comparable to Merb (Rails wins in some benchmarks, Merb in others).  <strong>BUT&#8230;. Merb still blows away rails in startup time, by 2-3x. </strong>We thought we could take out our merb-routing hacks and reduce code complexity, but after watching production restarts, we decided to put it back.</p>
<p>This plugin can be found on github: <a style="text-decoration: none;" href="http://github.com/hungrymachine/merb_routing/tree/master" target="_blank">merb_routing</a></p>
<p>UPDATE: after talking to Carl Lerche, it sounds like the new router refactoring he is working on will support both syntaxes on the same codebase. That&#8217;ll be very cool.</p>
<img src="http://feeds.feedburner.com/~r/hungrymachine/~4/kscfdP4PHk4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.hungrymachine.com/2008/12/29/merb-routing-in-rails/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Sorry Mephisto.. Moving to WordPress</title>
		<link>http://blog.hungrymachine.com/2008/12/09/sorry-mephisto-moving-to-wordpress/</link>
		<comments>http://blog.hungrymachine.com/2008/12/09/sorry-mephisto-moving-to-wordpress/#comments</comments>
		<pubDate>Tue, 09 Dec 2008 18:56:21 +0000</pubDate>
		<dc:creator>aaron</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://blog2.hungrymachine.com/2008/12/09/sorry-mephisto-moving-to-wordpress/</guid>
		<description><![CDATA[Dear Mephisto, you&#8217;ve been great. We&#8217;ve been dating for a while, and I didnt have any complaints. but I&#8217;m sorta sick of writing blog posts in your web UI. I heard there are plugins for 0.8 for metaweblog api support, but after putzing around with rails 2.0 vs 2.2, etc&#8230; I decided to break up [...]]]></description>
			<content:encoded><![CDATA[<blockquote style="clear: both"><p>Dear Mephisto, you&#8217;ve been great. We&#8217;ve been dating for a while, and I didnt have any complaints. but I&#8217;m sorta sick of writing blog posts in your web UI. I heard there are plugins for 0.8 for metaweblog api support, but after putzing around with rails 2.0 vs 2.2, etc&#8230; I decided to break up with you. It&#8217;s really because I wanted to play with <a href="http://www.drinkbrainjuice.com/blogo" target="_blank">blogo</a>. No hard feelings. Lets be friends.</p></blockquote>
<blockquote style="clear: both"><p>Hi WordPress. How are you?</p></blockquote>
<p style="clear: both">We just ported our blog to WordPress. To import all our old content, I found <a href="http://schwuk.com/articles/2008/03/25/thy-will-be-done-m2wppy-is-released" target="_blank">m2wp.pl</a>, which after adding some mysql patches, does a great job of generating a wordpress export file that imports perfectly from the WP admin UI. It was missing a few features, like correct author attribution, so I make some tweaks and put it on <a href="http://github.com/hungrymachine/mephisto_to_wordpress/tree/master" target="_blank">github</a> if anyone is interested.</p>
<p style="clear: both">BTW, whats blogo?</p>
<p style="clear: both"><a class="image-link" href="http://twitter.com/lrz/status/1041024849"><img style=" text-align: center; display: block; margin: 0 auto 10px;" src="http://blog.hungrymachine.com/wp-content/uploads/2008/12/picture-32.png" alt="" width="400" height="168" /></a>Sor far I like.</p>
<p style="clear: both">One feature request for us techies, an easy TextMate &#8220;insert code here&#8221; feature.</p>
<p style="clear: both">UPDATE: don&#8217;t forget to cp your assets.</p>
<p><br class="final-break" style="clear: both" /></p>
<img src="http://feeds.feedburner.com/~r/hungrymachine/~4/X2c1oBNP_KM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.hungrymachine.com/2008/12/09/sorry-mephisto-moving-to-wordpress/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Modular routing in rails and merb (acts_as_routing)</title>
		<link>http://blog.hungrymachine.com/2008/11/26/acts_as_routing-modular-routing-in-rails-and-merb/</link>
		<comments>http://blog.hungrymachine.com/2008/11/26/acts_as_routing-modular-routing-in-rails-and-merb/#comments</comments>
		<pubDate>Wed, 26 Nov 2008 18:29:00 +0000</pubDate>
		<dc:creator>warren</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">blog.hungrymachine.com/2008/11/26/acts_as_routing-modular-routing-in-rails-and-merb</guid>
		<description><![CDATA[Here&#8217;s a proof of concept plugin that will monkeypatch Rails or Merb routing to allow you to define &#8220;acts as blocks&#8221; anywhere throughout your application (i.e. a plugin) and then use them in your routes file.
Imagine the plugin acts_as_commentable defines the following in its init.rb:


ActionController::Routing.routes_for_acts_as(:commentable) do &#124;map&#124;
  map.resources :comments
  map.best_comment '/best-comment', :controller =&#62; [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a proof of concept plugin that will monkeypatch Rails or Merb routing to allow you to define &#8220;acts as blocks&#8221; anywhere throughout your application (i.e. a plugin) and then use them in your routes file.<br />
Imagine the plugin acts_as_commentable defines the following in its init.rb:</p>
<div class="CodeRay">
<div class="code">
<pre><span style="color:#036; font-weight:bold">ActionController</span>::<span style="color:#036; font-weight:bold">Routing</span>.routes_for_acts_as(<span style="color:#A60">:commentable</span>) <span style="color:#080; font-weight:bold">do</span> |map|
  map.resources <span style="color:#A60">:comments</span>
  map.best_comment <span style="background-color:#fff0f0"><span style="color:#710">'</span><span style="color:#D20">/best-comment</span><span style="color:#710">'</span></span>, <span style="color:#A60">:controller</span> =&gt; <span style="background-color:#fff0f0"><span style="color:#710">'</span><span style="color:#D20">comments</span><span style="color:#710">'</span></span>, <span style="color:#A60">:action</span> =&gt; <span style="background-color:#fff0f0"><span style="color:#710">'</span><span style="color:#D20">best</span><span style="color:#710">'</span></span>
<span style="color:#080; font-weight:bold">end</span></pre>
</div>
</div>
<p>If you added these :acts_as to your config/routes.rb:</p>
<div class="CodeRay">
<div class="code">
<pre><span style="color:#036; font-weight:bold">ActionController</span>::<span style="color:#036; font-weight:bold">Routing</span>::<span style="color:#036; font-weight:bold">Routes</span>.draw <span style="color:#080; font-weight:bold">do</span> |map|
  map.resources <span style="color:#A60">:people</span>, <span style="color:#A60">:acts_as</span> =&gt; [<span style="color:#A60">:commentable</span>]
  map.resources <span style="color:#A60">:posts</span>, <span style="color:#A60">:acts_as</span> =&gt; [<span style="color:#A60">:commentable</span>]
<span style="color:#080; font-weight:bold">end</span></pre>
</div>
</div>
<p>You could then use these routes throughout your application:</p>
<div class="CodeRay">
<div class="code">
<pre>  &lt;%=person_comments_path(<span style="color:#036; font-weight:bold">Person</span>.first)%&gt;
  &lt;%=post_comments_path(<span style="color:#036; font-weight:bold">Post</span>.first)%&gt;
  &lt;%=person_best_comment_path(<span style="color:#036; font-weight:bold">Person</span>.first)%&gt;</pre>
</div>
</div>
<p>This is equivalent to doing:</p>
<div class="CodeRay">
<div class="code">
<pre><span style="color:#036; font-weight:bold">ActionController</span>::<span style="color:#036; font-weight:bold">Routing</span>::<span style="color:#036; font-weight:bold">Routes</span>.draw <span style="color:#080; font-weight:bold">do</span> |map|
  map.resources <span style="color:#A60">:people</span> <span style="color:#080; font-weight:bold">do</span> |people_map|
    people_map.resources <span style="color:#A60">:comments</span>
    people_map.best_comment <span style="background-color:#fff0f0"><span style="color:#710">'</span><span style="color:#D20">/best-comment</span><span style="color:#710">'</span></span>, <span style="color:#A60">:controller</span> =&gt; <span style="background-color:#fff0f0"><span style="color:#710">'</span><span style="color:#D20">comments</span><span style="color:#710">'</span></span>, <span style="color:#A60">:action</span> =&gt; <span style="background-color:#fff0f0"><span style="color:#710">'</span><span style="color:#D20">best</span><span style="color:#710">'</span></span>
  <span style="color:#080; font-weight:bold">end</span>
  map.resources <span style="color:#A60">:posts</span> <span style="color:#080; font-weight:bold">do</span> |posts_map|
    posts_map.resources <span style="color:#A60">:comments</span>
    posts_map.best_comment <span style="background-color:#fff0f0"><span style="color:#710">'</span><span style="color:#D20">/best-comment</span><span style="color:#710">'</span></span>, <span style="color:#A60">:controller</span> =&gt; <span style="background-color:#fff0f0"><span style="color:#710">'</span><span style="color:#D20">comments</span><span style="color:#710">'</span></span>, <span style="color:#A60">:action</span> =&gt; <span style="background-color:#fff0f0"><span style="color:#710">'</span><span style="color:#D20">best</span><span style="color:#710">'</span></span>
  <span style="color:#080; font-weight:bold">end</span>
<span style="color:#080; font-weight:bold">end</span></pre>
</div>
</div>
<p>The plugin is available on github: <a href="http://github.com/hungrymachine/acts_as_routing/tree/master ">http://github.com/hungrymachine/acts_as_routing/tree/master</a></p>
<p>P.S. At some point, I&#8217;ll submit patches to Rails and Merb so this functionality is native rather than provided via a monkeypatching plugin.</p>
<img src="http://feeds.feedburner.com/~r/hungrymachine/~4/v44bXqOfcHc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.hungrymachine.com/2008/11/26/acts_as_routing-modular-routing-in-rails-and-merb/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JRuby and why it might be nice to be back on the JVM – Part 2</title>
		<link>http://blog.hungrymachine.com/2008/11/21/jruby-and-why-it-might-be-nice-to-be-back-on-the-jvm-part-2/</link>
		<comments>http://blog.hungrymachine.com/2008/11/21/jruby-and-why-it-might-be-nice-to-be-back-on-the-jvm-part-2/#comments</comments>
		<pubDate>Fri, 21 Nov 2008 07:47:00 +0000</pubDate>
		<dc:creator>aaron</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[jruby]]></category>

		<guid isPermaLink="false">blog.hungrymachine.com/2008/11/21/jruby-and-why-it-might-be-nice-to-be-back-on-the-jvm-part-2</guid>
		<description><![CDATA[In the previous post, I did some JRuby testing and noticed perf improvements over time.
Mark Imbriaco, of 37Signals, asked how it compared to MRI. I was curious too.
I can&#8217;t promise a &#8220;clean&#8221; comparison, your mileage may vary, but&#8230; MRI was:

Completed in 552ms (View: 104, DB: 14) &#124; 200 OK [http://someurl.com/people/3]
Completed in 345ms (View: 60, DB: [...]]]></description>
			<content:encoded><![CDATA[<p>In the previous post, I did some <a href="http://blog.hungrymachine.com/2008/11/19/jruby-and-why-it-might-be-nice-to-be-back-on-the-jvm">JRuby testing</a> and noticed perf improvements over time.</p>
<p><a href="http://www.workingwithrails.com/person/6010-mark-imbriaco">Mark Imbriaco</a>, of 37Signals, asked how it compared to MRI. I was curious too.</p>
<p>I can&#8217;t promise a &#8220;clean&#8221; comparison, your mileage may vary, but&#8230; MRI was:</p>
<pre>
Completed in 552ms (View: 104, DB: 14) | 200 OK [http://someurl.com/people/3]
Completed in 345ms (View: 60, DB: <img src='http://blog.hungrymachine.com/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> | 200 OK [http://someurl.com/people/3]
Completed in 346ms (View: 60, DB: 4) | 200 OK [http://someurl.com/people/3]
Completed in 347ms (View: 56, DB: 4) | 200 OK [http://someurl.com/people/3]
Completed in 349ms (View: 58, DB: 5) | 200 OK [http://someurl.com/people/3]
</pre>
<p>Some stats on my runtime</p>
<pre>
$ java -version
java version "1.5.0_16"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b06-284)
Java HotSpot(TM) Client VM (build 1.5.0_16-133, mixed mode, sharing)
$ ruby -v
ruby 1.8.6 (2008-08-11 patchlevel 287) [i686-darwin9.5.0]
</pre>
<p>Both ran on a MacBook 2.53GHz.  Likely the perf is better on Java6?</p>
<p>Installed <a href="http://support.apple.com/downloads/Java_for_Mac_OS_X_10_5_Update_1">Java6</a> and re-ran. Similar but better results.</p>
<pre>
Completed in 8815ms (View: 1632, DB: 429) | 200 OK [http://someurl.com/people/3]
Completed in 1017ms (View: 656, DB: 25) | 200 OK [http://someurl.com/people/3]
Completed in 998ms (View: 618, DB: 18) | 200 OK [http://someurl.com/people/3]
Completed in 1300ms (View: 437, DB: 35) | 200 OK [http://someurl.com/people/3]
Completed in 315ms (View: 119, DB: 21) | 200 OK [http://someurl.com/people/3]
Completed in 361ms (View: 140, DB: 20) | 200 OK [http://someurl.com/people/3]
</pre>
<p>Wow! Thats damn close to MRI&#8230;eventually&#8230; JRuby warmup time sucks though. Maybe warm it up during deploy before putting it back into the load balancer?  Not exactly sure how to warm it correctly though.  </p>
<p>If you just hit a URL on your app, you&#8217;ll only warm up THAT execution path&#8230; and you cant hit all actions, so&#8230;. thoughts?</p>
<img src="http://feeds.feedburner.com/~r/hungrymachine/~4/WVJ0XQeRZMA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.hungrymachine.com/2008/11/21/jruby-and-why-it-might-be-nice-to-be-back-on-the-jvm-part-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JRuby and why it might be nice to be back on the JVM</title>
		<link>http://blog.hungrymachine.com/2008/11/19/jruby-and-why-it-might-be-nice-to-be-back-on-the-jvm/</link>
		<comments>http://blog.hungrymachine.com/2008/11/19/jruby-and-why-it-might-be-nice-to-be-back-on-the-jvm/#comments</comments>
		<pubDate>Wed, 19 Nov 2008 21:35:00 +0000</pubDate>
		<dc:creator>aaron</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[jruby]]></category>

		<guid isPermaLink="false">blog.hungrymachine.com/2008/11/19/jruby-and-why-it-might-be-nice-to-be-back-on-the-jvm</guid>
		<description><![CDATA[We ported our Rails application to JRuby in order to do some GC comparisons yesterday.  Not a ton of changes required. Mostly replacing gems with native dependencies. YAML is a bit more strict than its MRI counterpart&#8230;. but all told, thats pretty amazing!  Nice job JRuby crew!
That said&#8230;. one interesting, entirely un-scientific, test [...]]]></description>
			<content:encoded><![CDATA[<p>We ported our Rails application to JRuby in order to do some GC comparisons yesterday.  Not a ton of changes required. Mostly replacing gems with native dependencies. YAML is a bit more strict than its MRI counterpart&#8230;. but all told, thats pretty amazing!  Nice job JRuby crew!</p>
<p>That said&#8230;. one interesting, entirely un-scientific, test case.  After requesting the same URL 6 times, the VM got a lot better. 3.4s to 480ms</p>
<pre>
Completed in 3380ms (View: 2739, DB: 65) | 200 OK [http://someurl.com/people/3]
Completed in 1299ms (View: 1211, DB: 18) | 200 OK [http://someurl.com/people/3]
Completed in 1020ms (View: 949, DB: 20) | 200 OK [http://someurl.com/people/3]
Completed in 852ms (View: 732, DB: 18) | 200 OK [http://someurl.com/people/3]
Completed in 743ms (View: 628, DB: 31) | 200 OK [http://someurl.com/people/3]
Completed in 485ms (View: 374, DB: 14) | 200 OK [http://someurl.com/people/3]
</pre>
<p>It doesnt appear to be the DB caching the data. That time stayed consistent.</p>
<p> I didnt use any crazy runtime flags.. Just jetty, a war file, and -server&#8230;. </p>
<p>If it was something we were memcaching, then after the 2nd request, it would have been consistent. </p>
<p>The amount of time spent in the view improved dramatically. </p>
<p>I didnt think JRuby leveraged JIT&#8217;ing yet.  Anyone care to guess/explain why it was significantly better per request?</p>
<p>Note: It did trail off in the 300ms range with further testing&#8230;</p>
<img src="http://feeds.feedburner.com/~r/hungrymachine/~4/iM86QzRdwDw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.hungrymachine.com/2008/11/19/jruby-and-why-it-might-be-nice-to-be-back-on-the-jvm/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Are your mongrels growing by 20MB/request on Rails 2.2? Blame AssetTag!</title>
		<link>http://blog.hungrymachine.com/2008/11/19/are-your-mongrels-growing-to-600mb-blame-assettag/</link>
		<comments>http://blog.hungrymachine.com/2008/11/19/are-your-mongrels-growing-to-600mb-blame-assettag/#comments</comments>
		<pubDate>Thu, 20 Nov 2008 01:56:00 +0000</pubDate>
		<dc:creator>aaron</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[rails patches]]></category>

		<guid isPermaLink="false">blog.hungrymachine.com/2008/11/19/are-your-mongrels-growing-to-600mb-blame-assettag</guid>
		<description><![CDATA[After porting our production application to Rails 2.2, we noticed a major memory leak.
Beforehand, monit would restart instances a handful of times a day.  After Rails 2.2, monit restarted instances THOUSANDS of times a day.
This is a graph of one of our haproxy instances a couple days ago.

We looked at everything, including time spent [...]]]></description>
			<content:encoded><![CDATA[<p>After porting our production application to Rails 2.2, we noticed a major memory leak.</p>
<p>Beforehand, monit would restart instances a handful of times a day.  After Rails 2.2, monit restarted instances THOUSANDS of times a day.</p>
<p>This is a graph of one of our haproxy instances a couple days ago.</p>
<p><center><img src="http://blog.hungrymachine.com/assets/2008/11/19/Picture_79.png" style="padding:10px;width:680px"></center></p>
<p>We looked at everything, including time spent <a href="http://blog.hungrymachine.com/2008/11/8/how-to-save-100m-of-ram-per-mongrel">rewriting</a> <a href="http://blog.hungrymachine.com/2008/11/11/how-to-save-100m-of-ram-per-mongrel-part-2">Routes</a>, thinking that was the culprit. </p>
<p>This morning, we all sat around and fought the issue old school style. binary debugging&#8230; and found it: AssetTagHelper. See the patch <a href="http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1419-massive-memory-leak-in-assettag">here</a>.</p>
<p>The new thread-safe asset tag code keeps a static AssetTag::Cache = {}  of all asset_tags created (css,jss, and all images).</p>
<p>Internally, each AssetTag object keeps a reference to the controller and template objects, and in turn all instance variables you created in your request.  </p>
<p>What does that mean?  Say you have a people controller, that loads a person and their stuff, and you show images of their stuff via image_tag().</p>
<pre>
 class PeopleController < ApplicationController
   def show
     @person = Person.find(params[:id])
     @stuff = @people.stuff.find(:all, :limit => 30)
   end
 end
</pre>
<p> When image_tag() is called, it does rails magic to append file extensions, asset_ids, and the like.  To be smart, it caches those objects so it doesnt hit the file system<br />
to figure all that out on every request.  The problem is it puts it in a static cache, AssetTag::Cache.</p>
<p> So each PeopleController instance has a reference to 1 person and 30 Stuffs.  After 1000 people look at their pages, or better yet google crawls your site, you have 1k @controllers with a total of 1000 People Objects, and 1000*30 Stuff objects.  This would normally be fine.  The objects leave scope and get GC&#8217;ed. But, if you generate an image tag to an unique asset, AssetTag puts that into a cache, AssetTag::Cache, with a reference to the @controller of the request.  So All People and their Stuff are kept around forever, unable to be GC&#8217;ed&#8230;. every time a unique image is rendered via AssetTag. Eventually monit has to kill the process.</p>
<p>The <a href="http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1419-massive-memory-leak-in-assettag">patch</a> we just submitted does 2 things.</p>
<p> 1) It now keeps a cache of just the modified path strings, caching the file access stuff.  If you have tons of local images, reference them by fully qualified host. Thats better for lots of reasons. Cookie-less asset hosts with multiple subdomains FTW!</p>
<p> 2) It stops caching absolute URL paths. You cant do anything on the filesystem to verify them, and keeping a cache of those would also grow unbounded. We have millions of items in our system, each with a reference to an image.</p>
<p>Here is a graph of that haproxy today&#8230;  Sleeping&#8230;&#8230;&#8230;</p>
<p><center><img src="http://blog.hungrymachine.com/assets/2008/11/19/Picture_80.png" style="padding:10px;width:680px"></center></p>
<p>In order to do some testing of your own, here&#8217;s a simplistic after_filter you can add to application.rb (or is it now application_controller.rb?). Make sure you run this in production mode or with cache_classes = true.  As you click around your site, you should see that the cache retains references to controller instances, just to name a few.  After you apply the patch, you&#8217;ll see the cache is just strings.</p>
<pre>
 def assettag_cache
    puts "-"*80
    puts "[AssetTag::Cache] Now #{ActionView::Helpers::AssetTagHelper::AssetTag::Cache.size} items"
    ActionView::Helpers::AssetTagHelper::AssetTag::Cache.values.each do |asset_tag|
      if asset_tag === ActionView::Helpers::AssetTagHelper::AssetTag
        puts "   [Asset] #{asset_tag.instance_variable_get("@source")}  #{asset_tag.instance_variable_get("@controller").class.to_s}"
      else
        puts "   [Asset] #{asset_tag}"
      end
    end
  end
</pre>
<p>Ohh&#8230; and we havent given up on routes&#8230; Warren is working on some very interesting enhancements to rails routing.  Looking forward to blogging about that soon.</p>
<img src="http://feeds.feedburner.com/~r/hungrymachine/~4/twe0gsJ6JRI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.hungrymachine.com/2008/11/19/are-your-mongrels-growing-to-600mb-blame-assettag/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to save 100m of RAM per mongrel (Part 2)</title>
		<link>http://blog.hungrymachine.com/2008/11/11/how-to-save-100m-of-ram-per-mongrel-part-2/</link>
		<comments>http://blog.hungrymachine.com/2008/11/11/how-to-save-100m-of-ram-per-mongrel-part-2/#comments</comments>
		<pubDate>Tue, 11 Nov 2008 01:53:00 +0000</pubDate>
		<dc:creator>aaron</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">blog.hungrymachine.com/2008/11/13/how-to-save-100m-of-ram-per-mongrel-part-2</guid>
		<description><![CDATA[UPDATE I&#8217;ve added a patch to Rails Edge for this fix, which is much different than the patch below.  See here
In a previous article, I called out the massive memory usage of the default rails resource behavior, and it seems others have as well.  In an attempt to decrease the number of routes, [...]]]></description>
			<content:encoded><![CDATA[<p><b>UPDATE</b> I&#8217;ve added a patch to Rails Edge for this fix, which is much different than the patch below.  See <a href="http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1359-add-optional-format-argument-to-named-routes#ticket-1359-5">here</a></p>
<p>In a <a href="http://blog.hungrymachine.com/2008/11/8/how-to-save-100m-of-ram-per-mongrel">previous article</a>, I called out the massive memory usage of the default rails resource behavior, and it seems <a href="http://rails.lighthouseapp.com/projects/8994/tickets/1215-add-actions-and-formatted-options-to-mapresources#ticket-1215-18">others</a> have as well.  In an attempt to decrease the number of routes, I commented out the &#8220;formatted_*&#8221; routes, and manually entered them back by hand.</p>
<p>But after some internal discussion/testing with Warren, we realized that was sloppy and error prone.  Instead, I hacked Routing segments to allow for an optional format segment, so that formatted routes and normal routes are shared.  The one downside, from what I can tell so far, is you lose &#8220;formatted_*&#8221; named routes + url helpers for those routes, but passing format to a url_for still works</p>
<pre>
   person_path(:id => 1, :format => "json") =>  /people/1.json
</pre>
<p> In the below gist, you&#8217;ll see a OptionalFormatSegment, which sneakily gets around the &#8216;.&#8217; regex separator, removes the formatted_* named routes added by default, and should be the same solution as the previous post, but without the need to manually put all the routes back in.  </p>
<p><script src="http://gist.github.com/23712.js"></script></p>
<p>I&#8217;m still testing this approach, but am interested in what other folks think.</p>
<p><b>Note:</b> This monkey-patch only works on Rails 2.2</p>
<img src="http://feeds.feedburner.com/~r/hungrymachine/~4/OG-TN_OgEKQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.hungrymachine.com/2008/11/11/how-to-save-100m-of-ram-per-mongrel-part-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss><!-- Dynamic page generated in 0.338 seconds. --><!-- Cached page generated by WP-Super-Cache on 2009-07-09 06:29:12 --><!-- Compression = gzip -->
