<?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>Todd Huss &#187; Web</title>
	<atom:link href="http://gabrito.com/post/category/technical/web/feed" rel="self" type="application/rss+xml" />
	<link>http://gabrito.com</link>
	<description>Anecdotes on Technology Leadership, Ruby, Java, Scala, Cloud Computing, Open-Source, SEO, and Design</description>
	<lastBuildDate>Thu, 08 Dec 2011 00:21:55 +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>Acceptance Testing non Ruby web applications with Cucumber</title>
		<link>http://gabrito.com/post/acceptance-testing-non-ruby-apps-with-cucumber</link>
		<comments>http://gabrito.com/post/acceptance-testing-non-ruby-apps-with-cucumber#comments</comments>
		<pubDate>Tue, 26 Oct 2010 21:49:18 +0000</pubDate>
		<dc:creator>Todd Huss</dc:creator>
				<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Quality Assurance]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://gabrito.com/?p=318</guid>
		<description><![CDATA[If you&#8217;re looking for the sample Standalone Cucumber Test Suite to get you started testing non Ruby based applications with Cucumber, here&#8217;s the source: http://github.com/thuss/standalone-cucumber. Sometimes you inherit a non Ruby based web app written in PHP, Perl, Java, C#, &#8230; <a href="http://gabrito.com/post/acceptance-testing-non-ruby-apps-with-cucumber">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://gabrito.com/wp-content/uploads/2010/10/cucumber-logo.png"><img src="http://gabrito.com/wp-content/uploads/2010/10/cucumber-logo.png" alt="" title="cucumber-logo" width="300" height="128" class="alignleft size-full wp-image-321" /></a>If you&#8217;re looking for the sample <a href="http://github.com/thuss/standalone-cucumber">Standalone Cucumber Test Suite</a> to get you started testing non Ruby based applications with Cucumber, here&#8217;s the source: <a href="http://github.com/thuss/standalone-cucumber">http://github.com/thuss/standalone-cucumber</a>.</p>
<p>Sometimes you inherit a non Ruby based web app written in PHP, Perl, Java, C#, or Python and you want to create an automated functional/acceptance test suite to minimize the amount of manual QA you need to do.<span id="more-318"></span> <a href="http://seleniumhq.org/">Selenium</a> is a great tool for doing just that and at <a href="http://www.commonsensemedia.org">Common Sense Media</a> I created the <a href="http://github.com/thuss/selenium-continuous-integration-runner">Selenium Continuous Integration Runner</a> to make it easy to run <a href="http://seleniumhq.org/docs/04_selenese_commands.html">Selenese</a> based tests from your <a href="http://en.wikipedia.org/wiki/Continuous_integration">Continuous Integration</a> Server such as Hudson, Cruise Control, or Teamcity. That said, Selenese based tests leave something to be desired in terms of readability and maintainability. </p>
<p>The <a href="http://www.ruby-lang.org/en/">Ruby</a> camp is often at the forefront of great testing frameworks with <a href="http://github.com/aslakhellesoy">Aslak Hellesøy</a> often leading the charge with innovations like <a href="http://rspec.info/">RSpec</a> and <a href="http://cukes.info/">Cucumber</a>. I&#8217;d read and played around with Cucumber on Rails based apps and was loving the concept of english language specs that are actually executable as well. But when my friend and former colleague Chris Kimm mentioned that the testing group at his company was using it to test their Java application, I started to get excited as that was the problem I was about to try and tackle at <a href="http://www.volunteermatch.org">VolunteerMatch</a>.</p>
<p>However, getting the project structure in place required a little help from the <a href="http://groups.google.com/group/cukes">Cucumber mailing list</a> and in the hopes of saving others the time, I&#8217;ve published the <a href="http://github.com/thuss/standalone-cucumber">Standalone Cucumber Test Suite</a> to  Github. It&#8217;s simply a Cucumber project designed to test a non Ruby web application with a sample search.feature that uses Google search as the basis for the test. It uses <a href="http://github.com/jnicklas/capybara">Capybara</a> with the <a href="http://seleniumhq.org/docs/09_webdriver.html">Selenium Webdriver</a> on the backend but you can also switch it to use <a href="http://github.com/langalex/culerity">Culerity</a> or <a href="http://github.com/brynary/webrat">Webrat</a> if you don&#8217;t want it actually firing up a real browser to run the tests.  Fork it or download it to start testing your existing website with Cucumber!</p>
]]></content:encoded>
			<wfw:commentRss>http://gabrito.com/post/acceptance-testing-non-ruby-apps-with-cucumber/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>iPhone development the easy way</title>
		<link>http://gabrito.com/post/iphone-development-the-easy-way</link>
		<comments>http://gabrito.com/post/iphone-development-the-easy-way#comments</comments>
		<pubDate>Wed, 08 Jul 2009 23:23:59 +0000</pubDate>
		<dc:creator>Todd Huss</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://gabrito.com/?p=250</guid>
		<description><![CDATA[Update 8/7/2010 PhoneGap apps are still being allowed in the app store! It&#8217;s not the right solution for every app (for example we went native with the Common Sense Media app), but I still think PhoneGap is really cool. I&#8217;ve &#8230; <a href="http://gabrito.com/post/iphone-development-the-easy-way">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><img src="http://gabrito.com/wp-content/uploads/2009/07/iphone.png" alt="iphone" title="iphone" width="76" height="104" class="alignleft size-full wp-image-251" /> <strong>Update 8/7/2010</strong> PhoneGap apps are <a href="http://blogs.nitobi.com/jesse/2010/04/14/phonegap-and-the-apple-developer-license-agreement/">still being allowed in the app store</a>! It&#8217;s not the right solution for every app (for example we went native with the <a href="http://www.commonsensemedia.org/iphone">Common Sense Media app</a>), but I still think PhoneGap is really cool.</p>
<p>I&#8217;ve been doing some iPhone and iPod Touch development and if like me you&#8217;re used to web development in languages like Ruby, Java, and Python, the learning curve to build a native iPhone app in Objective C is quite steep. Since my applications are online (in that you need to be connected for them to be useful) I was pysched to find a much easier way using two great open-source tools:</p>
<p><a href="http://code.google.com/p/iui/">iUI</a> consists of Javascript/CSS/images that allow you to build a mobile version of your app that looks and feels just like a native iPhone app</p>
<p><a href="http://phonegap.com/">PhoneGap</a> lets you create an iPhone application (that can be submitted to the app store) that displays a framed mobile version of your site</p>
<p>To build your iPhone app:<span id="more-250"></span></p>
<p>1. Make an iPhone/iPod Touch friendly version of your site with iUI (which your users can access in mobile safari)</p>
<p>2. Bundle it as an iPhone application (so the user has an app store version they can install) using PhoneGap and submit it to the app store. What&#8217;s even better is that with PhoneGap you can also target Blackberry and Android devices.</p>
<p>As a web developer I&#8217;m not sure how they could make it any easier for me, sweet! Plus you get the double exposure of the app store or when users visit your site with their iPhones they get the mobile version of your site.</p>
]]></content:encoded>
			<wfw:commentRss>http://gabrito.com/post/iphone-development-the-easy-way/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Transcending CSS</title>
		<link>http://gabrito.com/post/transcending-css</link>
		<comments>http://gabrito.com/post/transcending-css#comments</comments>
		<pubDate>Wed, 15 Aug 2007 16:14:51 +0000</pubDate>
		<dc:creator>Todd Huss</dc:creator>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://gabrito.com/post/transcending-css</guid>
		<description><![CDATA[Working at GreatSchools we do a lot of CSS work and we have a number of CSS books on our library shelf. However, last month we picked up a copy of Transcending CSS and it&#8217;s far and away the most &#8230; <a href="http://gabrito.com/post/transcending-css">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.amazon.com/gp/product/0321410971?ie=UTF8&#038;tag=marinewireles-20&#038;linkCode=as2&#038;camp=1789&#038;creative=390957&#038;creativeASIN=0321410971"><img border="0" src="http://ecx.images-amazon.com/images/I/61lTMGoALtL._SL160_.jpg" class="alignleft"></a><img src="http://www.assoc-amazon.com/e/ir?t=marinewireles-20&#038;l=as2&#038;o=1&#038;a=0321410971" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />Working at <a href="http://www.greatschools.net/">GreatSchools</a> we do a lot of CSS work and we have a number of CSS books on our library shelf. However, last month we picked up a copy of <a href="http://www.amazon.com/gp/product/0321410971?ie=UTF8&#038;tag=marinewireles-20&#038;link_code=as3&#038;camp=211189&#038;creative=373489&#038;creativeASIN=0321410971">Transcending CSS</a> and it&#8217;s far and away the most enlightening book on CSS I&#8217;ve read. We&#8217;re already changing the way we do our CSS for the better as a result.</p>
<p>Having worked with a lot of front-end<span id="more-180"></span> developers I can confirm that almost all of them would benefit from this book since most still </p>
<ul>
<li>use floats for layout as opposed to <a href="http://css-discuss.incutio.com/?page=AbsoluteLayouts">position absolute</a> (which is easily misunderstood because it&#8217;s positioning relative to the containing block)</li>
<li>few seem to regularly run their XHTML through a validator (a pet peeve of mine)</li>
<li>and even fewer seem to know to employ the concept of a <a href="http://developer.yahoo.com/yui/reset/">CSS reset</a></li>
</ul>
<p>It&#8217;s hard to convey all of the great stuff in this book but I can almost guarantee that if you work with CSS this book will open your eyes to a better way of doing things.</p>
]]></content:encoded>
			<wfw:commentRss>http://gabrito.com/post/transcending-css/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Open source caching proxy servers</title>
		<link>http://gabrito.com/post/open-source-caching-proxy-servers</link>
		<comments>http://gabrito.com/post/open-source-caching-proxy-servers#comments</comments>
		<pubDate>Tue, 22 May 2007 20:17:26 +0000</pubDate>
		<dc:creator>Todd Huss</dc:creator>
				<category><![CDATA[Systems Administration]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://gabrito.com/post/open-source-caching-proxy-servers</guid>
		<description><![CDATA[Hello lazy web, I&#8217;m looking for some advice on caching proxy servers and thought you might have some good pointers! We currently front our site with 3 caching proxy servers to offload static content from the web servers and we &#8230; <a href="http://gabrito.com/post/open-source-caching-proxy-servers">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.greatschools.net" title="Datacenter Diagram"><img class="alignleft" src="http://gabrito.com/wp-content/uploads/2007/05/datacenter.jpg" alt="Datacenter Diagram" /></a><br />
Hello lazy web, I&#8217;m looking for some advice on caching proxy servers and thought you might have some good pointers! </p>
<p>We currently front our site with 3 caching proxy servers to offload static content from the web servers and we haven&#8217;t found the right solution yet. We&#8217;ve tried a number of solutions including <a href="http://zipper.paco.net/~igor/oops.eng/">Oops</a> and <a href="http://httpd.apache.org/docs/2.0/mod/mod_cache.html">Apache with mod_cache</a> (which we&#8217;re currently running) but they are either missing a critical feature, have buggy caching behavior, or crash under heavy load. The main features I&#8217;m looking for are:<br />
<span id="more-176"></span><br />
1. Caches static content and pages and respects the expires header<br />
2. Can gzip content on the fly (this saves us a bundle in bandwidth costs)<br />
3. Can easily clear the cache when we move a new release live</p>
<p><!--adsense--></p>
<p>I&#8217;d prefer an open-source product but if we end up needing to go with a commercial solution as a last resort I&#8217;m open to that as well, thanks for your suggestions or help!</p>
]]></content:encoded>
			<wfw:commentRss>http://gabrito.com/post/open-source-caching-proxy-servers/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>GreatSchools wins Webby People&#8217;s Voice Award</title>
		<link>http://gabrito.com/post/greatschools-wins-the-webby-peoples-voice-award</link>
		<comments>http://gabrito.com/post/greatschools-wins-the-webby-peoples-voice-award#comments</comments>
		<pubDate>Tue, 01 May 2007 23:52:35 +0000</pubDate>
		<dc:creator>Todd Huss</dc:creator>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://gabrito.com/post/greatschools-wins-the-webby-peoples-voice-award</guid>
		<description><![CDATA[I&#8217;m thrilled that GreatSchools has won the Webby People&#8217;s Voice Award for best Family/Parenting site. We&#8217;ve been in the nominations before but I think continued growth and brand awareness through a largely redesigned site helped push us over the top &#8230; <a href="http://gabrito.com/post/greatschools-wins-the-webby-peoples-voice-award">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.webbyawards.com"><img  class="alignleft" alt="Webby People's Voice Award Winner" src="http://gabrito.com/files/webbypvwinner.jpg"/></a> I&#8217;m thrilled that <a href="http://www.greatschools.net">GreatSchools</a> has won the <a href="http://www.webbyawards.com/webbys/current.php?media_id=96&#038;season=11#webby_entry_family">Webby People&#8217;s Voice Award for best Family/Parenting site</a>. We&#8217;ve been in the nominations before but I think continued growth and brand awareness through a largely redesigned site helped push us over the top this year.<br />
<span id="more-175"></span><br />
I thought it would be fun to go back and look at how far the site has come in the 3 years that I&#8217;ve been at GreatSchools thanks in large part due to our kick ass product management and engineering teams. Here&#8217;s a look at our homepage in late 2003 compared to today May 2007 (<a href="http://picasaweb.google.com/todd.huss.work/GreatSchools20032007/photo#s5059740154630769074">here it is in slideshow format if you prefer that</a>): </p>
<p><a href="http://picasaweb.google.com/todd.huss.work/GreatSchools20032007/photo#5059740154630769074"><img src="http://lh4.google.com/image/todd.huss.work/RjfO3OyMCbI/AAAAAAAAAAo/TVrvpJYTw2M/s144/overview-old.jpg" /></a>&nbsp;&nbsp;&nbsp;<a href="http://picasaweb.google.com/todd.huss.work/GreatSchools20032007/photo#5059740154630769090"><img src="http://lh4.google.com/image/todd.huss.work/RjfO3OyMCcI/AAAAAAAAAAw/E1ryVRL7WAE/s144/overview-new.jpg" /></a></p>
<p>State landing page (now called Research and Compare)</p>
<p><a href="http://picasaweb.google.com/todd.huss.work/GreatSchools20032007/photo#5059740154630769106"><img src="http://lh4.google.com/image/todd.huss.work/RjfO3OyMCdI/AAAAAAAAAA4/0CgGefqzTlo/s144/researchcompare-old.jpg" /></a>&nbsp;&nbsp;&nbsp;<a href="http://picasaweb.google.com/todd.huss.work/GreatSchools20032007/photo#5059740154630769122"><img src="http://lh4.google.com/image/todd.huss.work/RjfO3OyMCeI/AAAAAAAAABA/FjOJI3nwHZw/s144/researchcompare-new.jpg" /></a></p>
<p>The school profile overview page:</p>
<p><a href="http://picasaweb.google.com/todd.huss.work/GreatSchools20032007/photo#5059740360789199346"><img src="http://lh4.google.com/image/todd.huss.work/RjfPDOyMCfI/AAAAAAAAABI/b2kOR8-t4pg/s144/sppoverview-old.jpg" /></a>&nbsp;&nbsp;&nbsp;<a href="http://picasaweb.google.com/todd.huss.work/GreatSchools20032007/photo#5059740360789199362"><img src="http://lh4.google.com/image/todd.huss.work/RjfPDOyMCgI/AAAAAAAAABQ/9u3TluXmSCg/s144/sppoverview-new.jpg" /></a></p>
<p>The city page:</p>
<p><a href="http://picasaweb.google.com/todd.huss.work/GreatSchools20032007/photo#5059740360789199378"><img src="http://lh4.google.com/image/todd.huss.work/RjfPDOyMChI/AAAAAAAAABY/tEaT0B4dtqM/s144/city-old.jpg" /></a>&nbsp;&nbsp;&nbsp;<a href="http://picasaweb.google.com/todd.huss.work/GreatSchools20032007/photo#5059740360789199394"><img src="http://lh4.google.com/image/todd.huss.work/RjfPDOyMCiI/AAAAAAAAABg/mxwCSgWdj4s/s144/city-new.jpg" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://gabrito.com/post/greatschools-wins-the-webby-peoples-voice-award/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Search engine cloaking, it&#8217;s the intent that matters</title>
		<link>http://gabrito.com/post/search-engine-cloaking-its-the-intent-that-matters</link>
		<comments>http://gabrito.com/post/search-engine-cloaking-its-the-intent-that-matters#comments</comments>
		<pubDate>Tue, 17 Apr 2007 01:01:32 +0000</pubDate>
		<dc:creator>Todd Huss</dc:creator>
				<category><![CDATA[Search Engine Optimization]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://gabrito.com/post/search-engine-cloaking-its-the-intent-that-matters</guid>
		<description><![CDATA[Back at the end of 2005 I wrote a short post titled Cloaking, no need to be ashamed and now in 2007 even more big sites are practicing some form of search engine crawler targeted cloaking. Yet still most SEO&#8217;s &#8230; <a href="http://gabrito.com/post/search-engine-cloaking-its-the-intent-that-matters">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Back at the end of 2005 I wrote a short post titled <a href="http://gabrito.com/post/cloaking-no-need-to-be-ashamed">Cloaking, no need to be ashamed</a> and now in 2007 even more big sites are practicing some form of <a href="http://en.wikipedia.org/wiki/Cloaking">search engine crawler targeted cloaking</a>. Yet still most SEO&#8217;s will give you a blanket answer and tell you to avoid cloaking so you don&#8217;t get delisted. I take a more pragmatic view and experience has taught me that certain forms of cloaking can be good!<br />
<span id="more-174"></span><br />
Cloaking all comes down to intent and to that end I&#8217;d like to illustrate a few legitimate (in my opinion) forms of cloaking in the real world:</p>
<p><!--adsense--></p>
<p>1. <strong><a href="http://www.amazon.com">Amazon.com</a></strong>: set your user agent to Googlebot and you won&#8217;t see a search box anymore. Crawlers don&#8217;t do forms and Amazon saves some bandwidth.<br />
2. <strong><a href="http://www.yahoo.com">Yahoo.com</a></strong>: almost every link is rewritten to go through a click tracking redirect but not so for crawlers. Yahoo doesn&#8217;t count the clicks from crawlers which is good for their metrics and the sites they link to get non redirected inbound links.<br />
3. <strong><a href="http://www.salon.com">Salon.com</a></strong>: crawlers get the real home page without having to see a full page ad first. I think I&#8217;ll start surfing Salon as Googlebot from now on <img src='http://gabrito.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /><br />
4. <strong><a href="http://www.cnn.com">CNN.com</a>, <a href="http://www.msn.com">MSN</a>, <a href="myspace.com">Myspace</a>, and <a href="http://www.ebay.com">EBay.com</a></strong>: crawlers don&#8217;t get served ad serving code saving bandwidth.</p>
<p>In all of the above cases these sites are serving adjusted content targeted to search engine user agents and generally it&#8217;s for the good. In the end the decision to cloak or not all comes down to good judgment and intent. If it helps crawlers avoid duplicate content or saves bandwidth then we shouldn&#8217;t be so quick to write off cloaking just because it has such a negative connotation. That said, if there&#8217;s any doubt in your mind be very weary and seek expert opinions because getting delisted for bad cloaking can result in a lot of lost revenue!</p>
]]></content:encoded>
			<wfw:commentRss>http://gabrito.com/post/search-engine-cloaking-its-the-intent-that-matters/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bay Area Indie Rock Bandega Style</title>
		<link>http://gabrito.com/post/bay-area-indie-rock-bandega-style</link>
		<comments>http://gabrito.com/post/bay-area-indie-rock-bandega-style#comments</comments>
		<pubDate>Wed, 14 Mar 2007 05:08:04 +0000</pubDate>
		<dc:creator>Todd Huss</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://gabrito.com/post/bay-area-indie-rock-bandega-style</guid>
		<description><![CDATA[My good friends in the east bay have just debuted their new Ruby on Rails based site Bandega :: never miss a show again! If you&#8217;re a San Francisco Bay Area resident that loves indie rock and wants to keep &#8230; <a href="http://gabrito.com/post/bay-area-indie-rock-bandega-style">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>My good friends in the east bay have just debuted their new Ruby on Rails based site <a href="http://bandega.com/">Bandega :: never miss a show again</a>! If you&#8217;re a San Francisco Bay Area resident that loves indie rock and wants to keep track of your favorite bands swing by <a href=" http://bandega.com/">Bandega</a> and check them out! </p>
]]></content:encoded>
			<wfw:commentRss>http://gabrito.com/post/bay-area-indie-rock-bandega-style/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Keeping Rails running at Dreamhost Part 2</title>
		<link>http://gabrito.com/post/keeping-rails-running-at-dreamhost-part-2</link>
		<comments>http://gabrito.com/post/keeping-rails-running-at-dreamhost-part-2#comments</comments>
		<pubDate>Thu, 25 Jan 2007 06:22:11 +0000</pubDate>
		<dc:creator>Todd Huss</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Systems Administration]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://gabrito.com/post/keeping-rails-running-at-dreamhost-part-2</guid>
		<description><![CDATA[Update 2/2/07: Per Thomas&#8217; comment I&#8217;ve released the code below as the dreamhost rails plugin. Update 1/25/07: People have reported difficulties copy and pasting the dispatch.fcgi source code from this blog post so here is a dispatch.fcgi to download. Make &#8230; <a href="http://gabrito.com/post/keeping-rails-running-at-dreamhost-part-2">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong>Update 2/2/07</strong>: Per Thomas&#8217; comment I&#8217;ve released the code below as the <a href="http://gabrito.com/post/ruby-on-rails-dreamhost-plugin">dreamhost rails plugin</a>.<br />
<strong>Update 1/25/07</strong>: People have reported difficulties copy and pasting the dispatch.fcgi source code from this blog post so here is a <a href="http://gabrito.com/files/dispatch.fcgi">dispatch.fcgi</a> to download. Make sure you make it executable!</p>
<p>My first attempt to keep my <a href="http://www.rubyonrails.org/">Ruby on Rails</a> sites running at <a href="http://www.dreamhost.com/r.cgi?241603">Dreamhost</a> involved <a href="http://wiki.dreamhost.com/index.php/Ruby_on_Rails">modifying dispatch.fcgi to implement the frao_handler approach as described on the wiki</a>. This left me with a 3% 500 error rate. Ughh!<br />
<span id="more-170"></span><br />
My second attempt involved <a href="http://gabrito.com/post/keeping-ruby-on-rails-running-at-dreamhost">gracefully restarting dispatch.fcgi&#8217;s every hour or two to avoid the wrath of the Dreamhost process monitor</a>. This reduced the 500 error rate down to 0.2% which was still too high!</p>
<p>I&#8217;ve finally gotten my 500 error rate down to 0 by making some minor changes to the signal handling code of dispatch.fcgi. If the dispatch.fcgi process is in the midst of handling a request I defer letting it be killed until the request is complete. I did this by installing a custom TERM signal handler that protects the dispatch.fcgi process while a request is being processed. This solution works for my Rails 1.1 and Rails 1.2 (previously Edge) based sites. Here&#8217;s my complete dispatch.fcgi:</p>
<p><!--adsense--></p>
<pre><span class="comment">#!/usr/bin/ruby1.8</span>

<span class="ident">require</span> <span class="constant">File</span><span class="punct">.</span><span class="ident">dirname</span><span class="punct">(</span><span class="constant">__FILE__</span><span class="punct">)</span> <span class="punct">+</span> <span class="punct">"</span><span class="string">/../config/environment</span><span class="punct">"</span>
<span class="ident">require</span> <span class="punct">'</span><span class="string">fcgi_handler</span><span class="punct">'</span>

<span class="keyword">class </span><span class="class">RailsFCGIHandler</span>
 <span class="ident">private</span>
   <span class="keyword">def </span><span class="method">busy_exit_handler</span><span class="punct">(</span><span class="ident">signal</span><span class="punct">)</span>
     <span class="ident">dispatcher_log</span> <span class="symbol">:info</span><span class="punct">,</span> <span class="punct">"</span><span class="string">busy: asked to terminate during request signal <span class="expr">#{signal}</span>, deferring!</span><span class="punct">"</span>
     <span class="attribute">@when_ready</span> <span class="punct">=</span> <span class="symbol">:exit</span>
   <span class="keyword">end</span>

   <span class="comment"># Dreamhost sends the term signal and if we're handling a request defer it</span>
   <span class="keyword">def </span><span class="method">term_process_request</span><span class="punct">(</span><span class="ident">cgi</span><span class="punct">)</span>
     <span class="ident">install_signal_handler</span><span class="punct">('</span><span class="string">TERM</span><span class="punct">',</span><span class="ident">method</span><span class="punct">(</span><span class="symbol">:busy_exit_handler</span><span class="punct">).</span><span class="ident">to_proc</span><span class="punct">)</span>
     <span class="constant">Dispatcher</span><span class="punct">.</span><span class="ident">dispatch</span><span class="punct">(</span><span class="ident">cgi</span><span class="punct">)</span>
   <span class="keyword">rescue</span> <span class="constant">Exception</span> <span class="punct">=></span> <span class="ident">e</span>  <span class="comment"># errors from CGI dispatch</span>
     <span class="keyword">raise</span> <span class="keyword">if</span> <span class="constant">SignalException</span> <span class="punct">===</span> <span class="ident">e</span>
     <span class="ident">dispatcher_error</span><span class="punct">(</span><span class="ident">e</span><span class="punct">)</span>
   <span class="keyword">ensure</span>
     <span class="ident">install_signal_handler</span><span class="punct">('</span><span class="string">TERM</span><span class="punct">',</span> <span class="ident">method</span><span class="punct">(</span><span class="symbol">:exit_now_handler</span><span class="punct">).</span><span class="ident">to_proc</span><span class="punct">)</span>
   <span class="keyword">end</span>
   <span class="ident">alias_method</span> <span class="symbol">:process_request</span><span class="punct">,</span> <span class="symbol">:term_process_request</span>
<span class="keyword">end</span>

<span class="constant">RailsFCGIHandler</span><span class="punct">.</span><span class="ident">process!</span></pre>
]]></content:encoded>
			<wfw:commentRss>http://gabrito.com/post/keeping-rails-running-at-dreamhost-part-2/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Keeping Ruby on Rails running at Dreamhost</title>
		<link>http://gabrito.com/post/keeping-ruby-on-rails-running-at-dreamhost</link>
		<comments>http://gabrito.com/post/keeping-ruby-on-rails-running-at-dreamhost#comments</comments>
		<pubDate>Wed, 10 Jan 2007 01:41:55 +0000</pubDate>
		<dc:creator>Todd Huss</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Systems Administration]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://gabrito.com/post/keeping-ruby-on-rails-running-at-dreamhost</guid>
		<description><![CDATA[Update 1/12/07: This solution has reduced my 500 error rate down to less than 0.2% but it&#8217;s still not perfect. I continue to plug away at this&#8230; Update 1/24/07: I&#8217;ve finally solved my Dreamhost 500 error problems with a different &#8230; <a href="http://gabrito.com/post/keeping-ruby-on-rails-running-at-dreamhost">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong>Update 1/12/07</strong>: This solution has reduced my 500 error rate down to less than 0.2% but it&#8217;s still not perfect. I continue to plug away at this&#8230;</p>
<p><strong>Update 1/24/07</strong>: I&#8217;ve finally solved my Dreamhost 500 error problems with a different solution described in <a href="http://gabrito.com/post/keeping-rails-running-at-dreamhost-part-2">Keeping Rails running at Dreamhost part 2<br />
</a><br />
This weekend I moved two of my newer <a href="http://www.rubyonrails.org/">Ruby on Rails</a> based sites (<a href="http://windandtides.com">http://windandtides.com</a> and <a href="http://gearandboats.com">http://gearandboats.com</a>) over to <a href="http://www.dreamhost.com/r.cgi?241603">Dreamhost</a>. You simply can&#8217;t beat their prices for hosting a small site (if you prepay for 2 years and use coupon code <strong>GABRITO</strong> to save $50 the total is $140.80) and I&#8217;ve found their customer service to be pretty responsive too.<br />
<span id="more-167"></span><br />
I followed their <a href="http://wiki.dreamhost.com/index.php/Ruby_on_Rails">Wiki based Ruby on Rails instructions</a> and had the sites up and running with <a href="http://manuals.rubyonrails.com/read/book/17">Capistrano</a> in no time. However, I soon discovered that their process monitor likes to kill off long running processes (effectively taking my sites offline without warning) and the only indication of what&#8217;s wrong is this error in the apache error.log:</p>
<p><!--adsense--></p>
<pre>
FastCGI: comm with (dynamic) server "/path/to/dispatch.fcgi" aborted: (first read)
  idle timeout (60 sec), referer: http://gearandboats.com
FastCGI: incomplete headers (0 bytes) received from server "/path/to/dispatch.fcgi",
  referer: http://gearandboats.com
</pre>
<p>To fix this I wrote a short ruby script <a href="http://gabrito.com/files/fcgimaint.rb">fcgimaint.rb</a> that I run once per hour via cron to restart my dispatch.fcgi processes (first with a USR1 and then a kill -9 if the USR1 didn&#8217;t work). This has the added benefit of cleaning up accumulated FastCGI processes and starting with a fresh memory footprint in case of a memory leak:</p>
<p>Crontab entry: 33  *  *  *  *  /home/myuser/bin/fcgimaint.rb</p>
<pre><span class="comment">#!/usr/bin/ruby</span>
<span class="keyword">def </span><span class="method">dispatchers</span><span class="punct">()</span>
  <span class="ident">ps</span> <span class="punct">=</span> `<span class="ident">ps</span> <span class="ident">ux`</span><span class="punct">.</span><span class="ident">grep</span><span class="punct">(/</span><span class="regex">dispatch<span class="escape">\.</span>fcgi</span><span class="punct">/)</span>
  <span class="ident">ps</span><span class="punct">.</span><span class="ident">map</span> <span class="punct">{|</span><span class="ident">p</span><span class="punct">|</span> <span class="punct">{'</span><span class="string">pid</span><span class="punct">'</span> <span class="punct">=></span> <span class="ident">p</span><span class="punct">.</span><span class="ident">split</span><span class="punct">[</span><span class="number">1</span><span class="punct">],</span> <span class="punct">'</span><span class="string">start</span><span class="punct">'</span> <span class="punct">=></span> <span class="ident">p</span><span class="punct">.</span><span class="ident">split</span><span class="punct">[</span><span class="number">8</span><span class="punct">]}}</span>
<span class="keyword">end</span>
<span class="ident">dispatchers</span><span class="punct">.</span><span class="ident">each</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">d</span><span class="punct">|</span> `<span class="ident">kill</span> <span class="punct">-</span><span class="constant">USR1</span> <span class="comment">#{d['pid']}` }</span>
<span class="ident">sleep</span> <span class="number">30</span>
<span class="comment"># Kill dispatchers that didn't restart nicely</span>
<span class="ident">dispatchers</span><span class="punct">.</span><span class="ident">each</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">d</span><span class="punct">|</span>
  <span class="keyword">if</span> <span class="punct">(</span><span class="constant">Time</span><span class="punct">.</span><span class="ident">now</span><span class="punct">.</span><span class="ident">hour</span> <span class="punct">!=</span> <span class="ident">d</span><span class="punct">['</span><span class="string">start</span><span class="punct">'][</span><span class="number">0</span><span class="punct">..</span><span class="number">1</span><span class="punct">])</span>
    `<span class="ident">kill</span> <span class="punct">-</span><span class="constant">KILL</span> <span class="comment">#{d['pid']}`</span>
  <span class="keyword">end</span>
<span class="keyword">end</span></pre>
<p>One other tool I found useful (especially during this process when the sites were going down periodically) was using <a href="http://nubyonrails.topfunky.com/articles/2006/03/29/surviving-rails-1-1-with-server-monitoring">Geoffrey Grosenbach&#8217;s modifications to dwatch to monitor my sites</a> and email my cell phone if there was a problem.<br />
<strong><br />
Caveat</strong>: if your site does more than 10,000 page views per day then a shared hosting plan is not the answer, you should be looking at dedicated or VPS hosting.</p>
]]></content:encoded>
			<wfw:commentRss>http://gabrito.com/post/keeping-ruby-on-rails-running-at-dreamhost/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Hello Newshutch, goodbye Bloglines</title>
		<link>http://gabrito.com/post/hello-newshutch-goodbye-bloglines</link>
		<comments>http://gabrito.com/post/hello-newshutch-goodbye-bloglines#comments</comments>
		<pubDate>Tue, 05 Dec 2006 02:54:34 +0000</pubDate>
		<dc:creator>Todd Huss</dc:creator>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[Blogging]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://gabrito.com/post/hello-newshutch-goodbye-bloglines</guid>
		<description><![CDATA[I&#8217;ve been a Bloglines user for a long time. However, after hearing about Newshutch on the Web 2.0 show podcast Episode 26 I&#8217;ve made the switch and couldn&#8217;t be happier. It sports just the right amount of Ajax, good keyboard &#8230; <a href="http://gabrito.com/post/hello-newshutch-goodbye-bloglines">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been a <a href="http://www.bloglines.com/">Bloglines</a> user for a long time. However, after hearing about <a href="http://www.newshutch.com/">Newshutch</a> on the <a href="http://www.web20show.com/">Web 2.0 show podcast</a> <a href="http://www.web20show.com/articles/2006/08/09/web-2-0-show-episode-26-newshutch">Episode 26</a> I&#8217;ve made the switch and couldn&#8217;t be happier. It sports just the right amount of Ajax, good keyboard shortcuts, and it&#8217;s built with Ruby on Rails. In short it&#8217;s by far the best web based RSS reader out there, <a href="http://www.newshutch.com">check it out</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://gabrito.com/post/hello-newshutch-goodbye-bloglines/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

