<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>Coffee Powered &#187; Chris Heald</title>
	<atom:link href="http://www.coffeepowered.net/author/cheald/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.coffeepowered.net</link>
	<description>code and content</description>
	<lastBuildDate>Mon, 09 Jan 2012 18:32:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Don&#8217;t use strip_tags.</title>
		<link>http://www.coffeepowered.net/2012/01/08/dont-use-strip_tags/</link>
		<comments>http://www.coffeepowered.net/2012/01/08/dont-use-strip_tags/#comments</comments>
		<pubDate>Sun, 08 Jan 2012 22:14:50 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=503</guid>
		<description><![CDATA[I ran into a rather surprising little problem earlier this week that I felt bore documenting. It turns out that the &#8220;simple&#8221; Rails strip_tags helper is massive overkill when you just want to strip markup out of a document. It offers a lot of functionality, but it comes at a pretty ugly performance cost. Here&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>I ran into a rather surprising little problem earlier this week that I felt bore documenting. It turns out that the &#8220;simple&#8221; Rails <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html#method-i-strip_tags">strip_tags</a> helper is <i>massive</i> overkill when you just want to strip markup out of a document. It offers a lot of functionality, but it comes at a pretty ugly performance cost.</p>
<p>Here&#8217;s the call graph for <code>#strip_tags</code> (as profiled in an application I&#8217;m working on). As you can see, it tokenizes the entire string, and then iterates the tokens, likely pushing and popping sections onto and off of a stack as tags are opened and closed.</p>
<p><a href="http://www.coffeepowered.net/wp-content/uploads/2012/01/strip_tags_call_graph.png"><img src="http://www.coffeepowered.net/wp-content/uploads/2012/01/strip_tags_call_graph.png" alt="" title="strip_tags_call_graph" width="100%" class="aligncenter size-medium wp-image-504" /></a></p>
<p>This is a lot more than a quick little regex to strip out tags; it&#8217;s actually parsing the full HTML document. Fortunately, there are already tools to do that, and they have their slow parts written as C extensions. <a href="http://nokogiri.org/">Nokogiri</a> is my weapon of choice in this regard &#8211; it&#8217;s battle-tested and generally rocks at parsing markup, even when it&#8217;s poorly-formed.</p>
<p>So, let&#8217;s benchmark a &#8220;strip all the markup out of a string&#8221; use case with <code>#strip_tags</code> and nokogiri.</p>
<pre class="brush: ruby; title: ; notranslate">
require 'rubygems'
require 'action_view'
require 'nokogiri'

include ActionView::Helpers::SanitizeHelper

f = open(&quot;news&quot;).read

LOOPS = 1000
Benchmark.bmbm do |x|
  x.report(&quot;strip_tags&quot;) { LOOPS.times { strip_tags f }}
  x.report(&quot;nokogiri&quot;) { LOOPS.times { Nokogiri::HTML(f).text }}
end
</pre>
<p>The data file in this case is a snapshot of the current page of <a href="http://news.ycombinator.com/">Hacker News</a>. It&#8217;s a 23kb HTML file. Nothing too huge, but certainly not small, either. Let&#8217;s run it through the benchmark:</p>
<pre class="brush: bash; title: ; notranslate">
[chris@luna projects]$ ruby strip.rb
Rehearsal ----------------------------------------------
strip_tags  33.070000   0.010000  33.080000 ( 33.092638)
nokogiri     3.220000   0.020000   3.240000 (  3.241090)
------------------------------------ total: 36.320000sec

                 user     system      total        real
strip_tags  33.010000   0.010000  33.020000 ( 33.056551)
nokogiri     3.190000   0.000000   3.190000 (  3.200680)
</pre>
<p>Yikes. It&#8217;s not just slower, it&#8217;s ~10x slower.</p>
<p>Don&#8217;t use <code>strip_tags</code>. Also, profile your code. But just because it&#8217;s convenient doesn&#8217;t mean you should use it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2012/01/08/dont-use-strip_tags/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Enabling brightness controls on an HP Envy 17 under Fedora 16</title>
		<link>http://www.coffeepowered.net/2011/11/13/enabling-brightness-controls-on-an-hp-envy-17-under-fedora-16/</link>
		<comments>http://www.coffeepowered.net/2011/11/13/enabling-brightness-controls-on-an-hp-envy-17-under-fedora-16/#comments</comments>
		<pubDate>Sun, 13 Nov 2011 21:01:15 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=485</guid>
		<description><![CDATA[I&#8217;ve recently set up Fedora 16 on my laptop, and all has been smooth, save for the brightness switches. The on-screen display would show up when I used the fn-F2/fn-F3 key combinations, but the brightness just wouldn&#8217;t change. Additionally, the brightness was stuck at the lowest level. Turns out there&#8217;s a pretty easy fix in [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently set up Fedora 16 on my laptop, and all has been smooth, save for the brightness switches. The on-screen display would show up when I used the fn-F2/fn-F3 key combinations, but the brightness just wouldn&#8217;t change. Additionally, the brightness was stuck at the lowest level.</p>
<p>Turns out there&#8217;s a pretty easy fix in the form of a couple of module parameters:</p>
<p>In /etc/defaults/grub, add the following kernel parameters:</p>
<pre class="brush: bash; title: ; notranslate">video.brightness_switch_enabled=1 video.use_bios_initial_backlight=0</pre>
<p>(You may also want to add <code>radeon.modeset=1</code> and <code>acpi_osi=Linux</code> for this particular machine, but they aren&#8217;t related to the brightness fix.)</p>
<p>Then update your grub2 config:</p>
<pre class="brush: bash; title: ; notranslate"> grub2-mkconfig &gt; /boot/grub2/grub.cfg </pre>
<p>Reboot, and your brightness controls should work as expected. The brightness slider in GNOME still doesn&#8217;t work, but I&#8217;m content with hardware brightness controls over no brightness controls.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2011/11/13/enabling-brightness-controls-on-an-hp-envy-17-under-fedora-16/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Comps &#8211; design vs reality comparisons in Chrome</title>
		<link>http://www.coffeepowered.net/2011/08/30/comps-design-vs-reality-comparisons-in-chrome/</link>
		<comments>http://www.coffeepowered.net/2011/08/30/comps-design-vs-reality-comparisons-in-chrome/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 03:45:38 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[chrome]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Original Software]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=481</guid>
		<description><![CDATA[For a long time, I used the PixelPerfect Firefox add-on to compare rendered comps with my finished web work. This was a fast and effective way to make sure that I got the spacings, font sizes, and other such things done properly. However, PixelPerfect doesn&#8217;t work all that well (well, at all) anymore, and Firefox [...]]]></description>
			<content:encoded><![CDATA[<p>For a long time, I used the <a href="https://addons.mozilla.org/en-US/firefox/addon/pixel-perfect/">PixelPerfect Firefox add-on</a> to compare rendered comps with my finished web work. This was a fast and effective way to make sure that I got the spacings, font sizes, and other such things done properly.</p>
<p>However, PixelPerfect doesn&#8217;t work all that well (well, at all) anymore, and Firefox is no longer my browser of choice. There weren&#8217;t any good options for Chrome, so I wrote one.</p>
<p>You can <a href="https://chrome.google.com/webstore/detail/ginhbdfcoiigpedgaidclojolemiincd">grab it straight from the Chrome store</a> if you want (it&#8217;s free!), or you might be interested in <a href="https://github.com/cheald/Comps">perusing the source code</a>.</p>
<p>Comps is very lightweight, and gets straight to the point &#8211; click the button, drop your comp into the webpage, and position it to make direct comparisons. Mousewheel over the comp to change its opacity, or you can toggle it on and off using the thumbnail drawer or the Comps button. It&#8217;ll remember your settings between sessions (and even pageloads!) so that you can tweak and refresh to your heart&#8217;s content, and instantly have your comp right there for comparison.</p>
<p>Give it a shot, let me know if/how you like it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2011/08/30/comps-design-vs-reality-comparisons-in-chrome/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails Cookie Sessions and PHP</title>
		<link>http://www.coffeepowered.net/2011/08/24/rails-cookie-sessions-and-php/</link>
		<comments>http://www.coffeepowered.net/2011/08/24/rails-cookie-sessions-and-php/#comments</comments>
		<pubDate>Wed, 24 Aug 2011 23:56:25 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[yaml]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=470</guid>
		<description><![CDATA[I recently found myself needing to share session data from my Rails app with a PHP app on the same domain. We use cookie sessions for a number of reasons, and while they work great, the data stored in them is stored in Ruby&#8217;s native Marshal format, which is not trivial to reimplement in PHP. [...]]]></description>
			<content:encoded><![CDATA[<p>I recently found myself needing to share session data from my Rails app with a PHP app on the same domain. We use cookie sessions for a number of reasons, and while they work great, the data stored in them is stored in Ruby&#8217;s native Marshal format, which is not trivial to reimplement in PHP. After trying to get the data unmarshaled for a bit, I had another idea &#8211; why not just change the storage format?</p>
<p>Fortunately, Ruby is deeply entangled with another more portable serialization format: YAML.</p>
<p>Rails manages its session cookies through the <a href="https://github.com/rails/rails/blob/2-3-stable/activesupport/lib/active_support/message_verifier.rb">MessageVerifier</a>. Easy enough &#8211; we can just write our own MessageVerifier that uses YAML rather than Marshal.</p>
<pre class="brush: ruby; title: ; notranslate">

module ActiveSupport
  class YamlMessageVerifier &lt; MessageVerifier
    def verify(signed_message)
      raise InvalidSignature if signed_message.blank?

      data, digest = signed_message.split(&quot;--&quot;)
      if data.present? &amp;&amp; digest.present? &amp;&amp; secure_compare(digest, generate_digest(data))
        str = ActiveSupport::Base64.decode64(data)
        if str[0..2] == '---'
          YAML::load str
        else # Handle old Marshal.dump'd session
          Marshal.load(str)
        end
      else
        raise InvalidSignature
      end
    end

    def generate(value)
      data = ActiveSupport::Base64.encode64s(YAML::dump value)
      &quot;#{data}--#{generate_digest(data)}&quot;
    end
  end
end
</pre>
<p>You&#8217;ll notice that verify() can accept a Marshaled session as well; this lets you transparently transition existing cookies to the new format without any kind of session breakage. Nice.</p>
<p>Now, to use the verifier, we monkeypatch CookieStore:</p>
<pre class="brush: ruby; title: ; notranslate">
module ActionController
  module Session
    class CookieStore
      def verifier_for(secret, digest)
        key = secret.respond_to?(:call) ? secret.call : secret
        ActiveSupport::YamlMessageVerifier.new(key, digest)
      end
    end
  end
end
</pre>
<p>Now, this will work&#8230;at least at first glance, until you try to use the flash. This is a particularly nasty little problem, and it stems from the fact that Ruby&#8217;s YAML implementation serializes Hash objects without their instance variables, and <a href="https://github.com/rails/rails/blob/2-3-stable/actionpack/lib/action_controller/flash.rb">FlashHash</a> inherits from Hash, and thus inherits its serialization/deserialization strategy. I worked for a while to monkeypatch those strategies, but I didn&#8217;t like the result, and it felt a little hacky. Instead, I just took advantage of the YAML load lifecycle to make sure the FlashHash initializes properly:</p>
<pre class="brush: ruby; title: ; notranslate">
module ActionController
  module Flash
    class FlashHash
      def update_with_initializer(h)
        @used ||= {}
        update_without_initializer(h)
      end
      alias_method_chain :update, :initializer
    end
  end
end
</pre>
<p>The core problem is that <code>YAML::load</code> calls <code>Hash#update</code>, and <code>FlashHash</code> presumes that the <code>@used</code> instance variable is present and initialized to an empty hash. To fix that, I just aliased in an initializer to make sure that variable is set.</p>
<p>Note that if you are storing other Hash subclasses with instance variables that rely on those variables being persisted across sessions, they will break. However, you should only be storing primitive/array/hash data in the session if possible. FlashHash is sort of a nasty violation of this principle.</p>
<p>At this point, your session should be serializing to and from YAML. We&#8217;ll want to read it from PHP, naturally. I&#8217;m using <a href="http://code.google.com/p/spyc/">SPYC</a> in the PHP project, which gets us Close Enough(TM). It doesn&#8217;t handle symbol keys, but we&#8217;ll handle those in the PHP itself.</p>
<h2>Reading from PHP</h2>
<p>Reading the data back out is surprisingly simple. We have to verify the authenticity of the data, of course, by checking the hash, but then you just base64 decode the data, load it with spyc, and perform some simple transformation to turn symbols into strings. If you wanted to make it even easier, you could monkeypatch the cookie store to call <code>#stringify_keys!</code> on your session hash before serializing it (and then call <code>#with_indifferent_access</code> on the hash when you deserialize it. Be aware of the speed impact of such a decision before you do it.)</p>
<pre class="brush: php; title: ; notranslate">
function explode_symbols($arr) {
  $result = array();
  foreach($arr as $key =&gt; $val) {
    if(is_numeric($key) &amp;&amp; $val[0] == &quot;:&quot;) {
      $bits = explode(&quot;:&quot;, $val, 3);
      $result[trim($bits[1])] = trim($bits[2]);
    } elseif (is_array($val)) {
      $result[$key] = explode_symbols($val);
    } else {
      $result[$key] = $val;
    }
  }
  return $result;
}

function deserialize_session($session_key, $secret) {
  list($session64, $hash) = explode(&quot;--&quot;, $_COOKIE[$session_key], 2);
  if(hash_hmac(&quot;SHA1&quot;, $session64, $secret) == $hash) {
    $session = base64_decode($session64);
    return explode_symbols(spyc_load($session));
  } else {
    throw new Exception(&quot;Invalid session signature&quot;);
  }
}

$rails_session = deserialize_session(&quot;your_session_cookie_name&quot;, $your_session_cookie_secret);
</pre>
<h2>Caveats</h2>
<ul>
<li>Be aware that YAML is slower than Marshal</li>
<li>Be aware that storing Hash subclasses in the session is likely going to Not Work.</li>
</ul>
<p>And that&#8217;s all there is to it. You can now share data between the two apps via the session cookie.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2011/08/24/rails-cookie-sessions-and-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Restarting Resque workers (or anything, really) with Monit, Passengers-style.</title>
		<link>http://www.coffeepowered.net/2011/08/19/restarting-resque-workers-or-anything-really-with-monit-passengers-style/</link>
		<comments>http://www.coffeepowered.net/2011/08/19/restarting-resque-workers-or-anything-really-with-monit-passengers-style/#comments</comments>
		<pubDate>Sat, 20 Aug 2011 05:15:10 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=467</guid>
		<description><![CDATA[Easy way to trigger off a reload of a service managed by Monit without having to become root. In my case, I&#8217;ve got a monit service called resque-worker, and I can restart it by just touching tmp/resque-restart.txt. Ties in nicely with deploy tasks, and you don&#8217;t have to end up leaving root access SSH keypairs [...]]]></description>
			<content:encoded><![CDATA[<p>Easy way to trigger off a reload of a service managed by Monit without having to become root. In my case, I&#8217;ve got a monit service called resque-worker, and I can restart it by just touching <code>tmp/resque-restart.txt</code>.</p>
<pre class="brush: plain; title: ; notranslate">
check file resque-restart.txt with path /path/to/your/app/tmp/resque-restart.txt
  if changed timestamp then
    exec &quot;/usr/bin/monit restart resque-worker&quot;
</pre>
<p>Ties in nicely with deploy tasks, and you don&#8217;t have to end up leaving root access SSH keypairs laying around.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2011/08/19/restarting-resque-workers-or-anything-really-with-monit-passengers-style/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB, count() and the big O</title>
		<link>http://www.coffeepowered.net/2011/07/17/mongodb-count-and-the-big-o/</link>
		<comments>http://www.coffeepowered.net/2011/07/17/mongodb-count-and-the-big-o/#comments</comments>
		<pubDate>Mon, 18 Jul 2011 00:04:55 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[mongomapper]]></category>
		<category><![CDATA[plucky]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=456</guid>
		<description><![CDATA[MongoDB, as I&#8217;ve mentioned before, is not without its warts. I&#8217;ve run into another, and it&#8217;s a nasty one. It turns out that if you perform count() on a query cursor that includes any conditions, even if those conditions are indexed, the operation takes O(n) time to run. In practice, I&#8217;ve found that this costs [...]]]></description>
			<content:encoded><![CDATA[<p>MongoDB, as I&#8217;ve mentioned before, is not without its warts. I&#8217;ve run into another, and it&#8217;s a nasty one. It turns out that if you perform <code>count()</code> on a query cursor that includes any conditions, even if those conditions are indexed, the operation takes <strong>O(n)</strong> time to run. </p>
<p>In practice, I&#8217;ve found that this costs about 1ms per 1000 records in your counted result set. This is <i>really</i> bad in concert with <a href="https://github.com/mislav/will_paginate">will_paginate</a>, which <a href="https://github.com/jnunemaker/plucky">Plucky</a> (which is used by <a href="http://mongomapper.com/">MongoMapper</a>) exposes an interface to. It naively takes your query, performs a <code>count()</code> on it, and then performs the query <em>again</em> with limiters to get the records for the current page. This is a standard and quickly-accepted way to do this sort of thing.</p>
<p>NewRelic is a great tool to help profile your applications, and in this case, it&#8217;s making the problem abundantly clear:</p>
<p><a href="http://www.coffeepowered.net/wp-content/uploads/2011/07/plucky.png"><img src="http://www.coffeepowered.net/wp-content/uploads/2011/07/plucky.png" alt="" title="NewRelic readout" width="100%" class="size-full wp-image-457" /></a></p>
<p>You see that purple? That&#8217;s how long it takes to run those <code>count()</code> operations. What a big fat pile of suck.</p>
<p>I don&#8217;t have a good solution to this yet, but in the meantime, I&#8217;ve mokneypatched Plucky to cache counts for large result sets. This means that my total counts for a large collection might desync over the course of an hour, but in my use cases, I only need ballpark numbers, so it works out well. This has a very noticeable effect on page times, effectively halving the amount of time I spend in the database for a given index page. Additionally, I can manually specify a count. So, for example, if I know a collection will have over 10k results, I can just pass 10k, and stop paginating after 10k results, drastically reducing my DB load at the expense of exposing older or long-tail content (which may be perfectly, appropriate, depending on the application context).</p>
<p>What I&#8217;m doing is caching any counts over some arbitrary limit (I chose 10k, at which point the counts would take ~10ms) for an hour via the Rails cache (memcached, in my case, leveraging the <code>expires_in</code> parameter). I brought the issue up in the #mongodb IRC channel, and the advice I was given was basically &#8220;cache your counts&#8221;, which is all well and good for simple data sets, but when I&#8217;m building pages per-user based on their preferences and myriad inputs (all indexed, mind you), it just doesn&#8217;t work, so I&#8217;ve resorted to this. It&#8217;s a hack, but it&#8217;s gotten my page times down substantially.</p>
<pre class="brush: ruby; title: ; notranslate">
module Plucky
  class Query
    BIG_RESULT_SET = 10000

    def paginate(opts={})
      page          = opts.delete(:page)
      limit         = opts.delete(:per_page) || per_page
      query         = clone.update(opts)
      cache_key     = &quot;count-cache-#{criteria.source.hash}&quot;
      total         = opts.delete(:total) || Rails.cache.read(cache_key)
      if total.nil?
        total       = query.count
        if total &gt; BIG_RESULT_SET
          Rails.cache.write(cache_key, total, :expires_in =&gt; 1.hour)
        end
      end
      paginator     = Pagination::Paginator.new(total, page, limit)
      query[:limit] = paginator.limit
      query[:skip]  = paginator.skip
      query.all.tap do |docs|
        docs.extend(Pagination::Decorator)
        docs.paginator(paginator)
      end
    end
  end
end</pre>
<p>I&#8217;m not entirely happy with this solution, and would love input on ways to fix it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2011/07/17/mongodb-count-and-the-big-o/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Resque and Tests</title>
		<link>http://www.coffeepowered.net/2011/07/15/resque-and-tests/</link>
		<comments>http://www.coffeepowered.net/2011/07/15/resque-and-tests/#comments</comments>
		<pubDate>Sat, 16 Jul 2011 04:23:50 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[redis]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=450</guid>
		<description><![CDATA[Resque is a bucket of awesome slathered in a delicious candy coating. It makes background job work really, *really* easy. I recently switched to it, and found that in the process of testing it, I was generating an awful lot of extra unfulfilled jobs in my queue, when the job was a side-effect of some [...]]]></description>
			<content:encoded><![CDATA[<p><a href="https://github.com/defunkt/resque">Resque</a> is a bucket of awesome slathered in a delicious candy coating. It makes background job work really, *really* easy. I recently switched to it, and found that in the process of testing it, I was generating an awful lot of extra unfulfilled jobs in my queue, when the job was a side-effect of some other test (rather than what was being tested explicitly).</p>
<p>I couldn&#8217;t find a quick and easy answer to this with some Googling, but it turns out that the answer is fortunately rather simple.<br />
<span id="more-450"></span><br />
In your <code>test_helper.rb</code>:</p>
<pre class="brush: ruby; title: ; notranslate">
 def setup
    Resque.redis.select 1
  end

  def teardown
    Resque.redis.keys(&quot;queue:*&quot;).each {|key| Resque.redis.del key }
  end
</pre>
<p>That&#8217;s all there is to it. The <code>setup</code> causes Resque to write to database #1 (#0 is default, and is what your development environment is likely using), and the <code>teardown</code> just deletes all your queues (which are really just lists of jobs to run). Test all you want and you won&#8217;t have to worry about tens of thousands of jobs junking up your redis DB.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2011/07/15/resque-and-tests/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: Warts and wobbles</title>
		<link>http://www.coffeepowered.net/2011/07/12/mongodb-warts-and-wobbles/</link>
		<comments>http://www.coffeepowered.net/2011/07/12/mongodb-warts-and-wobbles/#comments</comments>
		<pubDate>Tue, 12 Jul 2011 20:51:44 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[MongoDB]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=441</guid>
		<description><![CDATA[I&#8217;m a huge fan of MongoDB &#8211; after years in MySQL, Interbase, and Postgres SQL databases, it was quite a breath of fresh air to get to try a document database on for size. I&#8217;ve more or less adopted it as my default data store for web applications, due to a number of awesome features [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a huge fan of <a href="http://www.mongodb.org/">MongoDB</a> &#8211; after years in MySQL, Interbase, and Postgres SQL databases, it was quite a breath of fresh air to get to try a document database on for size. I&#8217;ve more or less adopted it as my default data store for web applications, due to a number of awesome features that many people have enumerated elsewhere. Rather than yet-another post about why MongoDB is great, I figured I&#8217;d talk about the things I don&#8217;t like in it, the places I&#8217;ve had difficulty with it, and the things I&#8217;d like to see improve. Knowing the sticky parts of a piece of technology is often as valuable &#8211; if not moreso &#8211; than knowing what it does really well. I absolutely still recommend it as a data store, but it&#8217;s not a magical panacea, and I want to take a realistic view of it.<br />
<span id="more-441"></span></p>
<h1>Wart #1: Case sensitivity</h1>
<p>All data in MongoDB is case-sensitive. This is in stark contrast to something like MySQL, where indexed text columns are case-insensitive. So, if you have a &#8220;username&#8221; field, &#8220;Chris&#8221; and &#8220;chris&#8221; could be two different users, and a user trying to log in as &#8220;chris&#8221; by tying &#8220;CHRIS&#8221; into the username field would fail their login attempt. You can solve this by either a) forcing a consistent casing (lower or upper) on the column, or b) by keeping a second shadow column with normalized (and indexed) data. So, for example, I might need to keep two columns, <code>username</code> and <code>shadow_username</code>, then index and do all queries against <code>shadow_username</code>, but display <code>username</code>. This isn&#8217;t a huge wart, but it&#8217;s going to bite you in the ass if you aren&#8217;t used to it.</p>
<h1>Wart #2: Aggregate queries</h1>
<p>SQL databases do aggregate queries <em>really</em> well. Consider a use case I had recently: I needed to find all accounts with duplicate emails.</p>
<p>In SQL, this is:</p>
<pre class="brush: sql; title: ; notranslate">SELECT email, count(id) as ct FROM users HAVING ct &gt; 1 GROUP BY email;</pre>
<p>In MongoDB, you have to do this with a map/reduce/finalize:</p>
<pre class="brush: jscript; title: ; notranslate">
var map = function() {
  if(this.email) {
    emit(this.email.toLowerCase(), {count: 1})
  }
}

var reduce = function(key, values) {
  var r = {count: 0};
  for(var i=0; i&lt;values.length; i++) {
    r.count += values[i].count;
  }
  return r;
}

db.users.mapReduce(map, reduce, {out: 'users.group_by_email'})
db.users.group_by_email.find({&quot;value.count&quot;: {$gt: 1}})
</pre>
<p>There are two warts here &#8211; the first is that as of MongoDB 1.7.4, you no longer have the option for temporary collections in MongoDB, and so you have to either A) write the whole result to a new collection, or B) return the whole result as a single document, but limited to 16MB of data. This means more maintenance &#8211; cleaning up old collections, notably. Secondly, it&#8217;s obviously a lot more code. The fact that M/R queries are written in Javascript is cool, but it&#8217;s kind of a pain in the ass to crank out a one-liner. Fortunately, because you are encouraged to store denormalized data in MongoDB, you don&#8217;t have to do as many of these sorts of queries, but when you do, it&#8217;s noticeably more painful than it would be with SQL.</p>
<h1>Wart #3: Timestamp sorting</h1>
<p>This is more of a bug than a design flaw, but it&#8217;s a nasty bug. MongoDB stores dates as <code>unsigned long long</code>, which is great, right? It gives you seriously far-future dates!</p>
<p>Until you want to sort a resultset by date that includes dates before 1970, that is (like, say, birthdays).</p>
<p>Since the storage type is unsigned, dates before the UNIX epoch get stored as very, very large numbers rather than as small negative numbers. You don&#8217;t notice this when you&#8217;re just querying data, but if you try to sort on a date column, any dates before 1970 will appear as being later than your other &#8220;normal&#8221; dates.</p>
<p>You might want to find all users who are more than 60 years old:</p>
<pre class="brush: jscript; title: ; notranslate">
db.users.find({birthday: {$lt: [Date Object for 60 years ago]}})
</pre>
<p>You&#8217;ll get an empty result set, because 60 years ago, in UNIX time, is -582954786, but you won&#8217;t ever have any results with a birthday indexed with a value of less than 0.</p>
<p>Likewise, if you want to get all users younger than a certain date:</p>
<pre class="brush: jscript; title: ; notranslate">
db.users.find({birthday: {$gt: [Date Object for 13 years ago]}})
</pre>
<p>You will get all users who were born before 1970 in this result set, since the index is simply looking at numeric long ranges, and pre-1970 dates will index very far future dates instead. <a href="https://jira.mongodb.org/browse/SERVER-405">This is fixed as of July 6th</a>, but won&#8217;t make it into production until Mongodb 1.10.</p>
<p>Workarounds:</p>
<p>* Map/Reduce users&#8217; ages into a separate collection periodically (once a month, perhaps?), then query off of that new collection.<br />
* Add some arbitrary amount of time to all birthdays in your application logic. For example, for birthdays, store the given birthday + 120 years, and then subtract 120 years before doing any calculations app-side with the birthday. This is an ugly hack, but requires no m/r maintenance.</p>
<h1>Wart #4: Arbitrary Javascript operations obtain a global lock</h1>
<p>Yesterday, I needed to fix a data problem; emails needed to be unique in my DB, but to check them, I needed a normalized lowercase email to query for. To do this, I had a simple bit of Javascript to execute:</p>
<pre class="brush: jscript; title: ; notranslate">
db.users.find().forEach(function(obj) {
  if(obj.email) {
    obj.email = obj.email.toLowerCase();
    db.users.save(obj);
  }
});</pre>
<p>Easy enough. Iterate each record, lowercase the email, save the record. Except when you give it a few hundred thousand records, with a bunch of indexes on the collection, it&#8217;s slooooow. My first naive crack at this locked my MongoDB master for several minutes, and didn&#8217;t complete before I killed it. During that time, the app was completely unresponsive. Oops.</p>
<p>I was able to rewrite the migration to be a lot faster, but you have to take a lot of care when running arbitrary data migrations, since you really can shoot yourself in the face easily with it.</p>
<pre class="brush: jscript; title: ; notranslate">
db.users.find().forEach(function(obj) {
  if(obj.email) {
    var email = obj.email.toLowerCase();
    if(email != obj.email) {
      db.users.update({_id: obj._id}, {$set: {email: email}});
    }
  }
});</pre>
<p>By a) only updating the record if the email changed, and b) using the atomic $set rather than updating the whole record, my migration ran in less than a second, rather than locking the entire application for minutes on end.</p>
<p>Be wary of that global lock. The official docs warn you about it, but the implications can&#8217;t be understated. Improvements to it are coming, but you&#8217;re going to nutpunch yourself with it eventually if you aren&#8217;t careful.</p>
<h1>Wart #5: $or queries and index hints</h1>
<p>MongoDB supports the $or operator for easy query unions, which makes life nice a lot of respects. However, it completely jacks up the query optimizer if you introduce sorting. What happens is that the query optimizer decides to use the sort field for the index, and results in a full table scan for each of your $or queries! Consider the following:</p>
<pre class="brush: jscript; title: ; notranslate">db.videos.find({$or: [{tags: {$all: ['b', 'a']}}, {tags: {$all: ['c', 'd']}}]})</pre>
<p>This will find the union of all documents that have tags &#8220;b&#8221; and &#8220;a&#8221; OR &#8220;c&#8221; and &#8220;d&#8221;. The tags index is used per subquery, resulting in a fast query.</p>
<p>But if you want to sort the results&#8230;</p>
<pre class="brush: jscript; title: ; notranslate">db.videos.find({$or: [{tags: {$all: ['b', 'a']}}, {tags: {$all: ['c', 'd']}}]}).sort({title: -1})</pre>
<p>MongoDB ignores the tags index for each of your $or clauses, and instead chooses to use the title index. This means that each of your $or clauses invokes a full table scan to find the tag matches, resulting in an extremely slow query. There is no way, as of right now, to tell the query optimizer to use the tags index when also using a sort on the cursor. Oops.</p>
<p>The accepted solution, right now, is to perform an in-app sort of the result set, which is a giant pain in the ass if you can&#8217;t prune the unsorted resultset to a reasonable size before sending it to the app before sorting. If in-app sorting isn&#8217;t an option for whatever reason, you&#8217;ll have to restructure your data to avoid the $or clause.</p>
<h1>A wobble: Document size</h1>
<p>One of MongoDB&#8217;s strengths can also be a weakness, if you&#8217;re not careful. Because you can store so much denormalized data in a single record, you can drastically reduce your number of queries, and build pages faster. However, it&#8217;s easy to forget that when you store all that data, you have to move it over the wire. Consider something like the following document:</p>
<pre class="brush: jscript; title: ; notranslate">topic: {name: 'Topic', description: 'A bit about this topic', followers: [array of follower BSON IDs]}</pre>
<p>This will work just fine in development. But what about in production, when that popular topic has 85,000 followers? All of a sudden, that&#8217;s 1,020,000 bytes that have to be sent over the wire every time you query that topic. What this really is is the old <code>SELECT *</code> problem, but magnified 100x. It&#8217;s ridiculously easy to accidentally end up with pages that are pulling tens of megabytes of data from the database server for every request, which does not scale well at all. Be judicious in your use of the field selection parameter when querying your database &#8211; your app will thank you.</p>
<p>To omit the followers array, I just omit the fields I don&#8217;t want in the query:</p>
<pre class="brush: jscript; title: ; notranslate">db.topics.find({name: 'Topic'}, {followers: false})</pre>
<p>Just a few little tweaks like this realized massive performance gains in my app, once I wasn&#8217;t moving tens of megabytes and instantiating thousands of BSON::ObjectId objects per record.</p>
<h1>Wrapping Up</h1>
<p>Despite the warts, none of these are reasons to decide to not use MongoDB. They introduce more work for you, and will make you pull your hair out in frustration if you naively wander into one of them by mistake, but if you&#8217;re aware of them, you can avoid them, and get all the good parts without having to taste too much of the bad. Like any piece of software, MongoDB has quirks and irritations, but if you aren&#8217;t buying into the hype that it&#8217;s a magical web-scale fix-all that mysteriously makes database and query design a non-issue, they aren&#8217;t that big of a deal. After all, now you know, and&#8230;</p>
<p><a href="http://www.coffeepowered.net/wp-content/uploads/2011/07/knowing-is-half-the-battle1.jpg"><img src="http://www.coffeepowered.net/wp-content/uploads/2011/07/knowing-is-half-the-battle1.jpg" alt="" title="knowing-is-half-the-battle1" width="395" height="192" class="aligncenter size-full wp-image-447" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2011/07/12/mongodb-warts-and-wobbles/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Tarot for easier Rails configurations</title>
		<link>http://www.coffeepowered.net/2011/06/28/tarot-for-easier-rails-configurations/</link>
		<comments>http://www.coffeepowered.net/2011/06/28/tarot-for-easier-rails-configurations/#comments</comments>
		<pubDate>Tue, 28 Jun 2011 23:04:11 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[tarot]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=432</guid>
		<description><![CDATA[Once upon a time, I wrote a quick-and-dirty Rails plugin for site configuration. Since then, I&#8217;ve continued to use variants on this pattern, and it&#8217;s evolved to the point that it deserved a revisit. After continually slimming down the code, I realized that even though it&#8217;s tiny, it&#8217;s danged useful to be able to just [...]]]></description>
			<content:encoded><![CDATA[<p>Once upon a time, I wrote a <a href="http://www.coffeepowered.net/2008/09/25/site_config-painless-config-variables-for-rails-projects/">quick-and-dirty Rails plugin for site configuration</a>. Since then, I&#8217;ve continued to use variants on this pattern, and it&#8217;s evolved to the point that it deserved a revisit.</p>
<p>After continually slimming down the code, I realized that even though it&#8217;s tiny, it&#8217;s <em>danged useful</em> to be able to just drop this into a Rails app and go. Thus, I&#8217;d like to present <a href="https://github.com/cheald/tarot">Tarot</a>, my Rails configuration solution.</p>
<p>Tarot&#8217;s current form is heavily inspired by the Rails I18n usage, and is very quick and easy to use in your app. The generator installs a sample yaml file at config/tarot.yml, as well as an initializer to bootstrap your configuration and provide a handy helper method for quick access to those config values.</p>
<p>Assuming you have a config file like so:</p>
<pre class="brush: yaml; title: ; notranslate">
---
base: &amp;base
  foo: bar
  nested:
    tree: value
  array:
    - value 1
    - value 2

development: &amp;development
  &lt;&lt;: *base

test: &amp;test
  &lt;&lt;: *base

production: &amp;production
  &lt;&lt;: *base
  foo: baz
</pre>
<p>You&#8217;ll notice that all the environments inherit from your base environment; this gives you an easy way to define common settings once, then override them per environment. Handy!</p>
<p>You could can access values by key, or by dot-delimited path:</p>
<pre class="brush: ruby; title: ; notranslate">
config('foo') =&gt; 'bar'
config('nested.tree') =&gt; value
</pre>
<p>Default values are similarly easy.</p>
<pre class="brush: ruby; title: ; notranslate">
config('foo.missing', 42) =&gt; 42
</pre>
<p>Finally, while Tarot will read your current application environment&#8217;s config, if you want to reach into another environment, that&#8217;s likewise easy:</p>
<pre class="brush: ruby; title: ; notranslate">
config('foo', nil, 'production') =&gt; 'baz'
</pre>
<p>As of 0.1.2, Tarot also supports method_missing invocation:</p>
<pre class="brush: ruby; title: ; notranslate">
Config = Tarot::Config.new('settings.yml', Rails.env)
Config.foo.bar.baz =&gt; &quot;bin&quot;
</pre>
<p>It also supports default values:</p>
<pre class="brush: ruby; title: ; notranslate"># Assuming foo has no subkey bar
Config.foo.bar(&quot;default&quot;) =&gt; &quot;default&quot;
</pre>
<p>But it&#8217;ll fail if you try to invoke method_missing on a non-leaf node</p>
<pre class="brush: ruby; title: ; notranslate">
# Assuming that there is no `blaze` tree
Config.blaze.blarg =&gt; NameError
</pre>
<p>That&#8217;s about all there is to it &#8212; config isn&#8217;t (or shouldn&#8217;t be) a hard problem, so there&#8217;s not a whole lot to it, but it should get you up and running with easily-configured Rails apps in seconds.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2011/06/28/tarot-for-easier-rails-configurations/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Sexy CSS Scrollbars in Chrome</title>
		<link>http://www.coffeepowered.net/2011/06/17/sexy-css-scrollbars/</link>
		<comments>http://www.coffeepowered.net/2011/06/17/sexy-css-scrollbars/#comments</comments>
		<pubDate>Sat, 18 Jun 2011 05:20:01 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[CSS]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=426</guid>
		<description><![CDATA[It&#8217;s like it&#8217;s 1996 all over again, except with less suck. Webkit now supports styleable scrollbars, and you get to use all the Webkit CSS3 goodies, like gradients and rounded corners and the like. If you&#8217;re using Chrome or Safari, you might notice that I have the blog theme rocking super sexy grey scrollbars now, [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s like it&#8217;s 1996 all over again, except with less suck. Webkit now supports styleable scrollbars, and you get to use all the Webkit CSS3 goodies, like gradients and rounded corners and the like. If you&#8217;re using Chrome or Safari, you might notice that I have the blog theme rocking super sexy grey scrollbars now, which really ties the whole theme together. It&#8217;s pretty easy, too.</p>
<p><span id="more-426"></span></p>
<p>If you&#8217;re just here for the code, here&#8217;s the quick and dirty. I grabbed this from <a href="http://beautifulpixels.com/goodies/create-custom-webkit-scrollbar/">Beautiful Pixels</a> and adapted it to my needs.</p>
<pre class="brush: css; title: ; notranslate">
::-webkit-scrollbar {
  width: 13px;
  height: 13px; }

::-webkit-scrollbar:hover {
  height: 18px; }

::-webkit-scrollbar-button:start:decrement,
::-webkit-scrollbar-button:end:increment {
  height: 15px;
  width: 13px;
  display: block;
  background: #101211;
  background-repeat: no-repeat; }

::-webkit-scrollbar-button:horizontal:decrement {
  background-image: url(scrollbar/horizontal-decrement-arrow.png);
  background-position: 4px 3px; }

::-webkit-scrollbar-button:horizontal:increment {
  background-image: url(scrollbar/horizontal-increment-arrow.png);
  background-position: 3px 3px; }

::-webkit-scrollbar-button:vertical:decrement {
  background-image: url(scrollbar/vertical-decrement-arrow.png);
  background-position: 3px 4px; }

::-webkit-scrollbar-button:vertical:increment {
  background-image: url(scrollbar/vertical-increment-arrow.png);
  background-position: 3px 4px; }

::-webkit-scrollbar-button:horizontal:decrement:active {
  background-image: url(scrollbar/horizontal-decrement-arrow-active.png); }

::-webkit-scrollbar-button:horizontal:increment:active {
  background-image: url(scrollbar/horizontal-increment-arrow-active.png); }

::-webkit-scrollbar-button:vertical:decrement:active {
  background-image: url(scrollbar/vertical-decrement-arrow-active.png); }

::-webkit-scrollbar-button:vertical:increment:active {
  background-image: url(scrollbar/vertical-increment-arrow-active.png); }

::-webkit-scrollbar-track-piece {
  background-color: #151716; }

::-webkit-scrollbar-thumb:vertical {
  height: 50px;
  background: -webkit-gradient(linear, left top, right top, color-stop(0%, #4d4d4d), color-stop(100%, #333333));
  border: 1px solid #0d0d0d;
  border-top: 1px solid #666666;
  border-left: 1px solid #666666; }

::-webkit-scrollbar-thumb:horizontal {
  width: 50px;
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #4d4d4d), color-stop(100%, #333333));
  border: 1px solid #1f1f1f;
  border-top: 1px solid #666666;
  border-left: 1px solid #666666; }
</pre>
<p><code>::-webkit-scrollbar</code> defines the height and width of your scrollbars for horizontal and vertical scroll bars, respectively.</p>
<p><code>::-webkit-scrollbar-button:start:decrement</code> and <code>::-webkit-scrollbar-button:end:increment</code> style the arrows on either end of the scroll bar. I have mine set to 1px black bars, but you could add an image, or a gradient, or whatnot.</p>
<p><code>::-webkit-scrollbar-track-piece</code> sets styles for the background of the scrollbar (called the &#8220;track&#8221; here)</p>
<p><code>::-webkit-scrollbar-thumb:vertical</code> and <code>::-webkit-scrollbar-thumb:horizontal</code> set styles for the draggable portion of the scroll bar. Background images, gradients, round corners, and even box shadows are all valid here. Go nuts.</p>
<p>With just those pieces, you should be able to crank out awesome-looking theme-fitting scroll bars. Have fun with it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2011/06/17/sexy-css-scrollbars/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

