<?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:atom="http://www.w3.org/2005/Atom" xmlns:posterous="http://posterous.com/help/rss/1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
  <channel>
    <title>Patch Engineering</title>
    <link>http://engineering.patch.com</link>
    <description>Most recent posts at Patch Engineering</description>
    <generator>posterous.com</generator>
    <link xmlns="http://www.w3.org/2005/Atom" href="http://posterous.com/api/sup_update#de80ce29d" type="application/json" rel="http://api.friendfeed.com/2008/03#sup" />
    
    
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/PatchEngineering" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="patchengineering" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://posterous.superfeedr.com/" /><item>
      <pubDate>Thu, 14 Oct 2010 12:21:00 -0700</pubDate>
      <title>Taming Bundler</title>
      <link>http://engineering.patch.com/taming-bundler</link>
      <guid>http://engineering.patch.com/taming-bundler</guid>
      <description>
        <![CDATA[<p>
	<p>Bundler is the bomb for gem dependency management, but do you ever get sick of having to <code>bundle install</code> each time you switch git branches?</p>

<p>What happens is when you run your app, Bundler will cache some information (like your app&rsquo;s load path) in <code>.bundle/environment.rb</code>. When you switch branches, the Gemfile may change underneath it, leaving the environment file stale. Now Bundler needs to ask you to rebuild your environment by running <code>bundle install</code>.</p>

<p>The solution? Maintain a per-branch bundler environment. Here&rsquo;s how:</p>

<p>Put this file somewhere useful &ndash; either your home directory, or commit it into your project for others to use:</p>

<p><div class="data type-shell">
    
      <table class="lines" cellspacing="0" cellpadding="0">
        <tr>
          <td>
            <pre class="line_numbers"><span rel="#L1" id="L1">1</span>
<span rel="#L2" id="L2">2</span>
<span rel="#L3" id="L3">3</span>
<span rel="#L4" id="L4">4</span>
<span rel="#L5" id="L5">5</span>
<span rel="#L6" id="L6">6</span>
<span rel="#L7" id="L7">7</span>
<span rel="#L8" id="L8">8</span>
<span rel="#L9" id="L9">9</span>
<span rel="#L10" id="L10">10</span>
<span rel="#L11" id="L11">11</span>
<span rel="#L12" id="L12">12</span>
<span rel="#L13" id="L13">13</span>
<span rel="#L14" id="L14">14</span>
<span rel="#L15" id="L15">15</span>
<span rel="#L16" id="L16">16</span>
<span rel="#L17" id="L17">17</span>
<span rel="#L18" id="L18">18</span>
<span rel="#L19" id="L19">19</span>
<span rel="#L20" id="L20">20</span>
<span rel="#L21" id="L21">21</span>
<span rel="#L22" id="L22">22</span>
<span rel="#L23" id="L23">23</span>
<span rel="#L24" id="L24">24</span>
<span rel="#L25" id="L25">25</span>
<span rel="#L26" id="L26">26</span>
<span rel="#L27" id="L27">27</span>
<span rel="#L28" id="L28">28</span>
<span rel="#L29" id="L29">29</span>
<span rel="#L30" id="L30">30</span>
<span rel="#L31" id="L31">31</span>
<span rel="#L32" id="L32">32</span>
<span rel="#L33" id="L33">33</span>
<span rel="#L34" id="L34">34</span>
<span rel="#L35" id="L35">35</span>
<span rel="#L36" id="L36">36</span>
<span rel="#L37" id="L37">37</span>
<span rel="#L38" id="L38">38</span>
<span rel="#L39" id="L39">39</span>
<span rel="#L40" id="L40">40</span>
<span rel="#L41" id="L41">41</span>
<span rel="#L42" id="L42">42</span>
<span rel="#L43" id="L43">43</span>
<span rel="#L44" id="L44">44</span>
<span rel="#L45" id="L45">45</span>
<span rel="#L46" id="L46">46</span>
<span rel="#L47" id="L47">47</span>
<span rel="#L48" id="L48">48</span>
<span rel="#L49" id="L49">49</span>
<span rel="#L50" id="L50">50</span>
<span rel="#L51" id="L51">51</span>
<span rel="#L52" id="L52">52</span>
<span rel="#L53" id="L53">53</span>
<span rel="#L54" id="L54">54</span>
<span rel="#L55" id="L55">55</span>
<span rel="#L56" id="L56">56</span>
<span rel="#L57" id="L57">57</span>
<span rel="#L58" id="L58">58</span>
<span rel="#L59" id="L59">59</span>
<span rel="#L60" id="L60">60</span>
<span rel="#L61" id="L61">61</span>
<span rel="#L62" id="L62">62</span>
<span rel="#L63" id="L63">63</span>
<span rel="#L64" id="L64">64</span>
<span rel="#L65" id="L65">65</span>
<span rel="#L66" id="L66">66</span>
<span rel="#L67" id="L67">67</span>
<span rel="#L68" id="L68">68</span>
<span rel="#L69" id="L69">69</span>
<span rel="#L70" id="L70">70</span>
<span rel="#L71" id="L71">71</span>
<span rel="#L72" id="L72">72</span>
<span rel="#L73" id="L73">73</span>
<span rel="#L74" id="L74">74</span>
<span rel="#L75" id="L75">75</span>
<span rel="#L76" id="L76">76</span>
<span rel="#L77" id="L77">77</span>
<span rel="#L78" id="L78">78</span>
<span rel="#L79" id="L79">79</span>
<span rel="#L80" id="L80">80</span>
<span rel="#L81" id="L81">81</span>
<span rel="#L82" id="L82">82</span>
<span rel="#L83" id="L83">83</span>
<span rel="#L84" id="L84">84</span>
<span rel="#L85" id="L85">85</span>
</pre>
          </td>
          <td width="100%">
            
              
                <div class="highlight"><pre /><div class="line" id="LC1"><span class="c">#!/bin/sh</span></div><div class="line" id="LC2"><br /></div><div class="line" id="LC3"><span class="c">######################################################################</span></div><div class="line" id="LC4"><span class="c">#</span></div><div class="line" id="LC5"><span class="c"># switch_bundler_environment OLD-BRANCH NEW-BRANCH</span></div><div class="line" id="LC6"><span class="c">#</span></div><div class="line" id="LC7"><span class="c"># Swap out the old branch&#39;s Bundler environment, and swaps in the new</span></div><div class="line" id="LC8"><span class="c"># branch&#39;s. Arguments may be branch names or SHAs.</span></div><div class="line" id="LC9"><span class="c">#</span></div><div class="line" id="LC10"><span class="c"># For best results, add this to .git/hooks/post-checkout:</span></div><div class="line" id="LC11"><span class="c">#</span></div><div class="line" id="LC12"><span class="c">#     #!/bin/sh</span></div><div class="line" id="LC13"><span class="c">#     exec script/switch_bundler_environment $1 $2</span></div><div class="line" id="LC14"><span class="c">#</span></div><div class="line" id="LC15"><span class="c">######################################################################</span></div><div class="line" id="LC16"><br /></div><div class="line" id="LC17">branch<span class="o">()</span></div><div class="line" id="LC18"><span class="o">{</span></div><div class="line" id="LC19">&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">local </span><span class="nv">branchish</span><span class="o">=</span><span class="nv">$1</span></div><div class="line" id="LC20">&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="o">[</span> -f <span class="s2">&quot;.git/refs/heads/$branchish&quot;</span> <span class="o">]</span>; <span class="k">then</span></div><div class="line" id="LC21"><span class="k">        </span><span class="nb">echo</span> <span class="s2">&quot;$branchish&quot;</span></div><div class="line" id="LC22">&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">else</span></div><div class="line" id="LC23"><span class="k">        for </span>f in .git/refs/heads/*; <span class="k">do</span></div><div class="line" id="LC24"><span class="k">            if</span> <span class="o">[</span> -f <span class="s2">&quot;$f&quot;</span> <span class="o">]</span>; <span class="k">then</span></div><div class="line" id="LC25"><span class="k">                </span><span class="nb">local </span><span class="nv">name</span><span class="o">=</span><span class="k">$(</span>basename <span class="nv">$f</span><span class="k">)</span></div><div class="line" id="LC26">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="o">[</span> <span class="s2">&quot;$(cat .git/refs/heads/$name)&quot;</span> <span class="o">=</span> <span class="s2">&quot;$branchish&quot;</span> <span class="o">]</span>; <span class="k">then</span></div><div class="line" id="LC27"><span class="k">                    </span><span class="nb">echo</span> <span class="s2">&quot;$name&quot;</span></div><div class="line" id="LC28">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">fi</span></div><div class="line" id="LC29"><span class="k">            fi</span></div><div class="line" id="LC30"><span class="k">        done</span></div><div class="line" id="LC31"><span class="k">    fi</span></div><div class="line" id="LC32"><span class="o">}</span></div><div class="line" id="LC33"><br /></div><div class="line" id="LC34">save<span class="o">()</span></div><div class="line" id="LC35"><span class="o">{</span></div><div class="line" id="LC36">&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">local </span><span class="nv">branch</span><span class="o">=</span><span class="nv">$1</span></div><div class="line" id="LC37">&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="o">[</span> -n <span class="nv">$branch</span> <span class="o">]</span>; <span class="k">then</span></div><div class="line" id="LC38"><span class="k">        </span>copy_directory .bundle <span class="s2">&quot;.branch_bundles/$branch/bundle&quot;</span></div><div class="line" id="LC39">&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">fi</span></div><div class="line" id="LC40"><span class="o">}</span></div><div class="line" id="LC41"><br /></div><div class="line" id="LC42">load<span class="o">()</span></div><div class="line" id="LC43"><span class="o">{</span></div><div class="line" id="LC44">&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">local </span><span class="nv">branch</span><span class="o">=</span><span class="nv">$1</span></div><div class="line" id="LC45">&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="o">[</span> -n <span class="nv">$branch</span> <span class="o">]</span>; <span class="k">then</span></div><div class="line" id="LC46"><span class="k">        </span>copy_directory <span class="s2">&quot;.branch_bundles/$branch/bundle&quot;</span> .bundle</div><div class="line" id="LC47">&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">fi</span></div><div class="line" id="LC48"><span class="o">}</span></div><div class="line" id="LC49"><br /></div><div class="line" id="LC50">copy_directory<span class="o">()</span></div><div class="line" id="LC51"><span class="o">{</span></div><div class="line" id="LC52">&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">local </span><span class="nv">src</span><span class="o">=</span><span class="nv">$1</span></div><div class="line" id="LC53">&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">local </span><span class="nv">dst</span><span class="o">=</span><span class="nv">$2</span></div><div class="line" id="LC54"><br /></div><div class="line" id="LC55">&nbsp;&nbsp;&nbsp;&nbsp;rm -rf <span class="s2">&quot;$dst&quot;</span></div><div class="line" id="LC56">&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="o">[</span> -d <span class="s2">&quot;$src&quot;</span> <span class="o">]</span>; <span class="k">then</span></div><div class="line" id="LC57"><span class="k">        </span>mkdir -p <span class="s2">&quot;$(dirname $dst)&quot;</span></div><div class="line" id="LC58">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cp -r <span class="s2">&quot;$src&quot;</span> <span class="s2">&quot;$dst&quot;</span></div><div class="line" id="LC59">&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">fi</span></div><div class="line" id="LC60"><span class="o">}</span></div><div class="line" id="LC61"><br /></div><div class="line" id="LC62"><span class="k">if</span> <span class="o">[</span> <span class="nv">$# </span>-ne 2 <span class="o">]</span>; <span class="k">then</span></div><div class="line" id="LC63"><span class="k">    </span><span class="nb">echo</span> <span class="s2">&quot;USAGE: #$0 FROM-BRANCHISH TO-BRANCHISH&quot;</span> &gt;&amp;2</div><div class="line" id="LC64">&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">exit </span>1</div><div class="line" id="LC65"><span class="k">fi</span></div><div class="line" id="LC66"><br /></div><div class="line" id="LC67"><span class="nv">old_branch</span><span class="o">=</span><span class="k">$(</span>branch <span class="nv">$1</span><span class="k">)</span></div><div class="line" id="LC68"><span class="nv">new_branch</span><span class="o">=</span><span class="k">$(</span>branch <span class="nv">$2</span><span class="k">)</span></div><div class="line" id="LC69"><br /></div><div class="line" id="LC70"><span class="k">if</span> <span class="o">[</span> -n <span class="s2">&quot;$old_branch&quot;</span> <span class="o">]</span>; <span class="k">then</span></div><div class="line" id="LC71"><span class="k">    </span>save <span class="nv">$old_branch</span></div><div class="line" id="LC72"><span class="k">fi</span></div><div class="line" id="LC73"><br /></div><div class="line" id="LC74"><span class="c"># If no bundler environment exists for the new branch, only kill the</span></div><div class="line" id="LC75"><span class="c"># existing one if the Gemfile is different. This way forking a new</span></div><div class="line" id="LC76"><span class="c"># branch off the current one doesn&#39;t require a &quot;bundle install&quot;.</span></div><div class="line" id="LC77"><span class="k">if</span> <span class="o">[</span> -n <span class="s2">&quot;$new_branch&quot;</span> -a                                        <span class="se">\</span></div><div class="line" id="LC78">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s1">&#39;(&#39;</span>                                                        <span class="se">\</span></div><div class="line" id="LC79">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d <span class="s2">&quot;.branch_bundles/$new_branch/bundle&quot;</span> -o               <span class="se">\</span></div><div class="line" id="LC80">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-n <span class="s2">&quot;$(git diff $old_branch:Gemfile $new_branch:Gemfile)&quot;</span> <span class="se">\</span></div><div class="line" id="LC81">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s1">&#39;)&#39;</span>                                                        <span class="se">\</span></div><div class="line" id="LC82">&nbsp;&nbsp;&nbsp;<span class="o">]</span>; <span class="k">then</span></div><div class="line" id="LC83"><span class="k">    </span>load <span class="nv">$new_branch</span></div><div class="line" id="LC84"><span class="k">fi</span></div><div class="line" id="LC85"><br /></div></pre></div>
              
            
          </td>
        </tr>
      </table>
    
  </div></p>

<p>Now add this to your repository&rsquo;s <code>.git/hooks/post-checkout</code> :</p>

<div class="CodeRay">
  <div class="code"><pre>#!/bin/sh
exec /path/to/that/script $1 $2</pre></div>
</div>


<p><strong>Make sure both files are executable!</strong></p>

<p>This will stash the old .bundle directory away, and swap in the one for the new branch each time you check out. Bundler never felt so smooth.</p>

<p>Happy bundling!</p>
	
</p>

<p><a href="http://engineering.patch.com/taming-bundler">Permalink</a> 

	| <a href="http://engineering.patch.com/taming-bundler#comment">Leave a comment&nbsp;&nbsp;&raquo;</a>

</p>]]>
      </description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5ewZwCavY2Ep</posterous:profileUrl>
        <posterous:firstName>George</posterous:firstName>
        <posterous:lastName>Ogata</posterous:lastName>
        <posterous:nickName>patch-george</posterous:nickName>
        <posterous:displayName>George Ogata</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Thu, 06 May 2010 15:38:34 -0700</pubDate>
      <title>Easily switch between multiple ruby interpreters using a four-line shell script</title>
      <link>http://engineering.patch.com/easily-switch-between-multiple-ruby-interpret</link>
      <guid>http://engineering.patch.com/easily-switch-between-multiple-ruby-interpret</guid>
      <description>
        <![CDATA[<p>
	<p>Just thought I'd share a little tip on some local environment setup I
did today. I'm a big fan of <a href="http://outofti.me/post/111132650/installing-alternate-ruby-versions-as-optional-packages">installing alternate Ruby versions as optional
packages</a>
(that means they live in /opt/package-name-version; not in a shared hierarchy
prefixed /opt, like MacPorts incorrectly does). Previously I'd mostly been using
this to run test suites against a
<a href="http://outofti.me/post/111117383/a-15-line-alternative-to-multiruby">bunch of different versions</a>,
but now that Patch using Enterprise Edition in production I'd like to be able
to switch my default ruby interpreter with minimum hassle.</p>

<p>Turns out it's really easy, and you don't need to install RVM and
install ruby interpreters in your home directory (why does everyone
seem to want to do that?). Here's what I did:</p>

<p>Create a directory <code>~/.ruby-opt</code></p>

<p>Write an executable shell script called <code>ruby-opt</code>, and put it somewhere in your
PATH (I have ~/bin in my PATH for this sort of thing). The shell script looks
like this:</p>

<div class="CodeRay">
  <div class="code"><pre>#!/bin/sh
export PACKAGE=`ls -d1 /opt/ruby-*$1* | head -n1`
echo &quot;Changing ruby interpreter to $PACKAGE&quot;
ln -sfv $PACKAGE/bin ~/.ruby-opt
ruby -v</pre></div>
</div>


<p>In your .bashrc, put this line:</p>

<div class="CodeRay">
  <div class="code"><pre>export PATH=~/.ruby-opt/bin:$PATH</pre></div>
</div>


<p>And you're done. The one catch here is that <em>all</em> the interpreters you
want to use have to be installed as optional packages. Now when you
want to switch versions, just run something like:</p>

<div class="CodeRay">
  <div class="code"><pre>$ ruby-opt 1.8.6</pre></div>
</div>


<p>The script uses wildcard expansion to find something in your /opt
directory that contains both "ruby" and the argument you passed, so
you only need to be specific enough for that to catch the right one.</p>
	
</p>

<p><a href="http://engineering.patch.com/easily-switch-between-multiple-ruby-interpret">Permalink</a> 

	| <a href="http://engineering.patch.com/easily-switch-between-multiple-ruby-interpret#comment">Leave a comment&nbsp;&nbsp;&raquo;</a>

</p>]]>
      </description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/417110/awesome-mat.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5eCiioSi1ZjX</posterous:profileUrl>
        <posterous:firstName>Mat</posterous:firstName>
        <posterous:lastName>Brown</posterous:lastName>
        <posterous:nickName>outoftime</posterous:nickName>
        <posterous:displayName>Mat Brown</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Thu, 22 Apr 2010 08:55:00 -0700</pubDate>
      <title>Quick, local short_urls</title>
      <link>http://engineering.patch.com/quick-local-shorturls</link>
      <guid>http://engineering.patch.com/quick-local-shorturls</guid>
      <description>
        <![CDATA[<p>
	<p>On patch.com, we generate short_urls for our editors to use on services like Twitter.  The benefit of generating the short URL internally is three-fold.  </p>
<ol>
<li>We get to maintain the Patch branding</li>
<li>We don't have to rely on an external shortening service</li>
<li>We can be in control of how our links are created</li>
</ol>
<p>The last one is really fun, because it means that we can cleverly name our short_urls in a way that they don't need to make an extra request to the database for lookup.  So, instead of a user requesting <strong><a href="http://patch.com/bE582">http://patch.com/bE582</a></strong>, and us looking up in a table what page that references, we can created a short URL like: <strong><a href="http://patch.com/L-dbrB">http://patch.com/L-dbrB</a></strong> and serve the user <span style="text-decoration: underline;">L</span>isting 281923.</p>
<p>Its really simple, as is the code to support it:</p>
<div class="CodeRay">
  <div class="code"><pre><code>
# John Crepezzi  April 22, 2010
class ShortId
  
  # We cute out vowels to avoid shortened strings from mistakenly forming words
  Alphabet = 'bcdfghjklmnpqrstvwxyz0123456789BCDFGHJKLMNPQRSTVWXYZ'
  AlphabetLength = Alphabet.length

  # Encode a numeric ID
  def self.encode(id)
    alpha = ''
    while id != 0
      alpha = Alphabet[id % AlphabetLength].chr + alpha
      id /= AlphabetLength
    end
    alpha
  end

  # Decode an ID created with self.encode
  def self.decode(alpha)
    alpha = alpha.dup; id = 0
    0.upto(alpha.length - 1) do |i|
      id += Alphabet.index(alpha[-1]) * (AlphabetLength ** i)
      alpha.chop!
    end
    id
  end

end
</code></pre></div>
</div>

<div class="CodeRay">
  <div class="code"><pre>Enjoy!</pre></div>
</div>
	
</p>

<p><a href="http://engineering.patch.com/quick-local-shorturls">Permalink</a> 

	| <a href="http://engineering.patch.com/quick-local-shorturls#comment">Leave a comment&nbsp;&nbsp;&raquo;</a>

</p>]]>
      </description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/502348/john.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5ebHsoPutFZv</posterous:profileUrl>
        <posterous:firstName>John</posterous:firstName>
        <posterous:lastName>Crepezzi</posterous:lastName>
        <posterous:nickName>john-at-patch</posterous:nickName>
        <posterous:displayName>John Crepezzi</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Fri, 02 Apr 2010 13:22:09 -0700</pubDate>
      <title>RakeServer is a client-server Rake architecture for fast task invocation</title>
      <link>http://engineering.patch.com/rakeserver-is-rake-a-client-server-architectu</link>
      <guid>http://engineering.patch.com/rakeserver-is-rake-a-client-server-architectu</guid>
      <description>
        <![CDATA[<p>
	<p>At Patch, as is generally the case with complex applications, we run quite a
few jobs in the background using cron &mdash; things like updating the current
weather, downloading new Twitter tweets, etc. Our general pattern is to have
<code>cron</code> invoke <code>rake</code> on whatever schedule makes sense to us.</p>

<p>This works well as far as it goes, but our app is quite beefy and it takes a
shall we say nontrivial amount of time to start. Since most of our scheduled
rake tasks require loading the environment, that ends up being a lot of time and
energy spent loading the environment to run a task that might only take a few
seconds. As they say, it doesn't really scale.</p>

<p>Enter <a href="http://github.com/outoftime/rake_server">RakeServer</a>, a tool Cedric and
I hacked up this week. The idea here is to run Rake tasks using a client-server
architecture, with a long-running server that responds to requests from clients
to invoke tasks. The crucial feature of RakeServer is that it can also invoke
tasks greedily when the server first starts &mdash; in particular the
<code>:environment</code> task, which loads the Rails environment. That way, when the
client invokes Rails-dependent tasks, the server is able to respond immediately
without waiting all that time for the environment to load.</p>

<p>A few other details of how RakeServer works, before we look at a typical (our)
use case. First, each time a task request is made, the server forks a child
process to actually run it -- so tasks can be run in parallel by different
clients if so desired. Second, the server captures the tasks' output via a pipe
and streams it back to the server, so the client ends up with the tasks' output
on stdout, a lot like if it were a normal invocation of Rake (note that right
now, there's no distinction made between stdout and stderr; it all goes to
stdout. That could change). The client process stays alive as long as the server
task is running, and then exits when it completes.</p>

<h3>OK, let's use this thing</h3>

<p>First, install the gem:</p>

<div class="CodeRay">
  <div class="code"><pre>$ sudo gem install rake_server</pre></div>
</div>


<p>Now we're going to set up a pre-fork and post-fork hook. If you naively fork the
Rails environment, ActiveRecord's database connection gets all messed up, so
your best bet is to disconnect from the database before forking and re-connect
afterwards.</p>

<p>Let's create a file <code>lib/tasks/rake_server.rake</code>:</p>

<div class="CodeRay">
  <div class="code"><pre>namespace :rake_server
  task :fork_hooks =&gt; :environment
    RakeServer::Server.before_fork { ActiveRecord::Base.remove_connection }
    RakeServer::Server.after_fork { ActiveRecord::Base.establish_connection }
  end
end</pre></div>
</div>


<p>Now, we can start <code>rake-server</code>. By default, RakeServer looks for your
<code>Rakefile</code> in all the same places Rake does:</p>

<div class="CodeRay">
  <div class="code"><pre>$ rake-server start rake_server:fork_hooks</pre></div>
</div>


<p>The first argument tells RakeServer to run in the background (<code>run</code> would run it
in the foreground); the other arguments are rake tasks to run immediately when
the server starts. In this case, we're going to set up our fork hooks, and also
load the environment (since the <code>:environment</code> task is a dependency of the
<code>:fork_hooks</code> task).</p>

<p>After a few seconds, you'll see output that rake-server is up and running:</p>

<div class="CodeRay">
  <div class="code"><pre>rake-server listening on 127.0.0.1:7253</pre></div>
</div>


<p>And finally, we can invoke a task!</p>

<div class="CodeRay">
  <div class="code"><pre>$ rake-client db:migrate</pre></div>
</div>


<p>And it's that easy, folks - you'll see your migrations start running right away.</p>

<p>RakeServer is still a young project and there are a few improvements I'd like to
make, but at a basic level, it's already working, so take it for a spin today.</p>
	
</p>

<p><a href="http://engineering.patch.com/rakeserver-is-rake-a-client-server-architectu">Permalink</a> 

	| <a href="http://engineering.patch.com/rakeserver-is-rake-a-client-server-architectu#comment">Leave a comment&nbsp;&nbsp;&raquo;</a>

</p>]]>
      </description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/417110/awesome-mat.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5eCiioSi1ZjX</posterous:profileUrl>
        <posterous:firstName>Mat</posterous:firstName>
        <posterous:lastName>Brown</posterous:lastName>
        <posterous:nickName>outoftime</posterous:nickName>
        <posterous:displayName>Mat Brown</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Thu, 04 Mar 2010 12:06:22 -0800</pubDate>
      <title>Sunspot 1.0 released!</title>
      <link>http://engineering.patch.com/sunspot-10-released</link>
      <guid>http://engineering.patch.com/sunspot-10-released</guid>
      <description>
        <![CDATA[<p>
	<p>Sunspot 1.0, long assumed to be vaporware, has finally arrived.
<a href="http://outoftime.github.com/2010/03/03/sunspot-1-0.html">Read about all the cool new features</a>.</p>
	
</p>

<p><a href="http://engineering.patch.com/sunspot-10-released">Permalink</a> 

	| <a href="http://engineering.patch.com/sunspot-10-released#comment">Leave a comment&nbsp;&nbsp;&raquo;</a>

</p>]]>
      </description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/417110/awesome-mat.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5eCiioSi1ZjX</posterous:profileUrl>
        <posterous:firstName>Mat</posterous:firstName>
        <posterous:lastName>Brown</posterous:lastName>
        <posterous:nickName>outoftime</posterous:nickName>
        <posterous:displayName>Mat Brown</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Thu, 18 Feb 2010 13:54:00 -0800</pubDate>
      <title>ActiveSupport Tip of the Day: Hash#slice, Hash#except</title>
      <link>http://engineering.patch.com/activesupport-tip-of-the-day-hashslice-hashex</link>
      <guid>http://engineering.patch.com/activesupport-tip-of-the-day-hashslice-hashex</guid>
      <description>
        <![CDATA[<p>
	<p>Recently, while working on a <a href="http://github.com/outoftime/native_support">side project</a>, I had occasion to pore methodically over the ActiveSupport library. I was surprised to find that, despite my having worked in Rails for a shade under two years, there were quite a few methods in ActiveSupport that I was unaware of -- some of them pretty useful!</p>
<p>This brings us to the first part of our four-hundred thirty-five part series, <strong>ActiveSupport Tip of the Day</strong> .</p>
<h4>Be picky about your hash keys</h4>
<p>Today's tip regards two methods defined on the <code>Hash</code> class: <code>slice</code> and <code>except</code>. <code>except</code> does exactly what you'd expect - it returns a new Hash with the specified keys removed. <code>slice</code> does the opposite of <code>except</code>, which isn't necessarily what you'd expect from the name, but oh well.</p>
<p>So here's how they work:</p>
<p><code>hash = {:a =&gt; 1, :b =&gt; 2, :c =&gt; 3, :d =&gt; 4} 
=&gt; {:a=&gt;1, :b=&gt;2, :c=&gt;3, :d=&gt;4} 
hash.slice(:a, :b) 
=&gt; {:a=&gt;1, :b=&gt;2} 
hash.except(:a, :b) 
=&gt; {:c=&gt;3, :d=&gt;4}</code></p>
<p>Not earth-shattering stuff, but these are definitely handy for filtering out an allowed set of options to pass into a method:</p>
<p><code><code>Post.all(:conditions =&gt; params.slice(:name, :category_id))</code><br /></code></p>
<p>Both methods also have bang-forms, which modify the hash in place rather than returning a new one.</p>
<p>That is all. Soldier on, soldiers.</p>
	
</p>

<p><a href="http://engineering.patch.com/activesupport-tip-of-the-day-hashslice-hashex">Permalink</a> 

	| <a href="http://engineering.patch.com/activesupport-tip-of-the-day-hashslice-hashex#comment">Leave a comment&nbsp;&nbsp;&raquo;</a>

</p>]]>
      </description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/417110/awesome-mat.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5eCiioSi1ZjX</posterous:profileUrl>
        <posterous:firstName>Mat</posterous:firstName>
        <posterous:lastName>Brown</posterous:lastName>
        <posterous:nickName>outoftime</posterous:nickName>
        <posterous:displayName>Mat Brown</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Fri, 12 Feb 2010 12:42:00 -0800</pubDate>
      <title>Why your IP blacklisting isn't working, and how to fix it</title>
      <link>http://engineering.patch.com/why-your-ip-blacklisting-isnt-working-and-how</link>
      <guid>http://engineering.patch.com/why-your-ip-blacklisting-isnt-working-and-how</guid>
      <description>
        <![CDATA[<p>
	<p>One of the major tools of spam prevention is IP blacklisting - if a given IP address belongs to a known spammer, then spam blockers like Akismet will consider it spam. So, let's say we're building a little spam checker in our comments controller:</p>
<div class="CodeRay">
  <div class="code"><pre><code># app/controllers/comments_controller.rb
class CommentsController
  def create
    viking = Viking::Akismet.new
    spam_response = viking.check_comment(
      :user_ip =&gt; request.remote_ip,
      :user_agent =&gt; request.user_agent
      # etc
    )
    if spam_response[:spam]
      render :status =&gt; 404
    else
      Comment.create(params[:comment])
      flash(&quot;Your comment was created!)
      redirect_to :back
    end
  end
end</code></pre></div>
</div>

<p>So far, so good. But let's say one day you're in the situation where you're Rails application container is running behind several other machines - perhaps a hardware load balancer, delegating out to an Apache instance, which goes to a haproxy instance, which finally load balances out to your thins. And let's say further that your data center isn't running behind a typical NAT system - so those intermediate machines don't have a 192.168 or 10. IP address.</p>
<p>As it turns out, in this case the <code>request.remote_ip</code> method will return the IP address of your load balancer, or whatever machine is sitting in front of you in the request chain. To figure out why, let's take a look at that method in Rails:</p>
<div class="CodeRay">
  <div class="code"><pre><code># lib/action_controller/request.rb
def remote_ip
  remote_addr_list = @env['REMOTE_ADDR'] &amp;&amp; @env['REMOTE_ADDR'].scan(/[^,\s]+/)

  unless remote_addr_list.blank?
    not_trusted_addrs = remote_addr_list.reject {|addr| addr =~ TRUSTED_PROXIES}
    return not_trusted_addrs.first unless not_trusted_addrs.empty?
  end
  # some more stuff here...
end
</code></pre></div>
</div>

<p>So what we're doing here is getting a list of all of the IPs of machines that this request has gone through on the way to your Rails instance. Then we return the first IP in that list that isn't considered a "trusted proxy".</p>
<div class="CodeRay">
  <div class="code"><pre><code>TRUSTED_PROXIES = /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
</code></pre></div>
</div>

<p>OK, so it's localhost, anything that starts with 10., and the usual suspects of 192.168 etc. But like I said before, you're not behind NAT, so your load balancer's IP doesn't match this list. As far as Rails is concerned, every request is coming from a load balancer, and you're not a spammer, are you?</p>
<p>The solution is pretty straightforward, and much easier than figuring out the problem: just modify that TRUSTED_PROXIES hash in an initializer. Here's how ours looks:</p>
<div class="CodeRay">
  <div class="code"><pre><code># config/initializers/trusted_proxies.rb
if CONFIG[:trusted_proxies]
  builtin_trusted_proxies = ActionController::Request::TRUSTED_PROXIES
  ActionController::Request.module_eval do
    remove_const(:TRUSTED_PROXIES)
    const_set(:TRUSTED_PROXIES, Regexp.union(builtin_trusted_proxies, Regexp.new(CONFIG[:trusted_proxies])))
  end
end</code></pre></div>
</div>

<p>All we're doing here is reading a list of trusted proxies (i.e., IPs or partial IPs in our data center) out of our <a href="http://railscasts.com/episodes/85-yaml-configuration-file">application config file</a>, and then merging it into the existing <code>TRUSTED_PROXIES</code> regexp.</p>
<p>Voila! Now <code>request.remote_ip</code> will actually evaluate to the IP of the requestor.</p>
	
</p>

<p><a href="http://engineering.patch.com/why-your-ip-blacklisting-isnt-working-and-how">Permalink</a> 

	| <a href="http://engineering.patch.com/why-your-ip-blacklisting-isnt-working-and-how#comment">Leave a comment&nbsp;&nbsp;&raquo;</a>

</p>]]>
      </description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/417110/awesome-mat.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5eCiioSi1ZjX</posterous:profileUrl>
        <posterous:firstName>Mat</posterous:firstName>
        <posterous:lastName>Brown</posterous:lastName>
        <posterous:nickName>outoftime</posterous:nickName>
        <posterous:displayName>Mat Brown</posterous:displayName>
      </posterous:author>
    </item>
  </channel>
</rss>

