<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>YARB - Home</title>
  <id>tag:shanti.railsblog.com,2008:mephisto/</id>
  <generator version="0.7.3" uri="http://mephistoblog.com">Mephisto Noh-Varr</generator>
  <link href="http://shanti.railsblog.com/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://shanti.railsblog.com/" rel="alternate" type="text/html"/>
  <updated>2008-07-09T04:30:47Z</updated>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-07-09:290</id>
    <published>2008-07-09T04:29:00Z</published>
    <updated>2008-07-09T04:30:47Z</updated>
    <link href="http://shanti.railsblog.com/getting-things-done-for-webapp-developers-gtd" rel="alternate" type="text/html"/>
    <title>Getting Things Done for Webapp Developers: GTD++</title>
<content type="html">
            &lt;p&gt;I wrote this a while back and had it archived on a Backpack page.&lt;/p&gt;


	&lt;p&gt;Since I&#8217;ve never done anything with it, thought I might as well post it here.&lt;/p&gt;


	&lt;p&gt;The ideas are very similar to &lt;a href=&quot;http://gettingreal.37signals.com/&quot;&gt;Getting Real&lt;/a&gt; by 37 Signals, though I don&#8217;t nearly flush them out as well.&lt;/p&gt;


	&lt;p&gt;Note: I wrote this after being frustrated at a few companies; I&#8217;ve since worked for some pretty cool teams that have actually adopted many of these ideas, under different names / etc (agile, XP, Getting Real, etc).&lt;/p&gt;


	&lt;h2&gt;How Webapp Developers Can Get More Done: &lt;span class=&quot;caps&quot;&gt;GTD&lt;/span&gt;++&lt;/h2&gt;


	&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;GTD&lt;/span&gt;++ is a collection of applied technologies and frameworks for agile, sustainable application development.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Version Control&lt;/li&gt;
		&lt;li&gt;Bug, Task &#38; Feature Request Tracking&lt;/li&gt;
		&lt;li&gt;One-step Builds&lt;/li&gt;
		&lt;li&gt;Unit Testing&lt;/li&gt;
		&lt;li&gt;Wiki / Knowledge Management&lt;/li&gt;
		&lt;li&gt;Automatic Documentation Extraction&lt;/li&gt;
		&lt;li&gt;Continuous Integration&lt;/li&gt;
		&lt;li&gt;Automated Application Testing (Web, &lt;span class=&quot;caps&quot;&gt;GUI&lt;/span&gt;, etc)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;&lt;strong&gt;Laws of &lt;span class=&quot;caps&quot;&gt;GTD&lt;/span&gt;++&lt;/strong&gt;&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Any ongoing process which relies upon the physical proximity of team members is inherently broken.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Any system that routinely relies upon verbal or message-based (non-captured) knowledge transfer for critical development work is inherently flawed.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Any process that can be automated in a functionally equivalent manner&#8212;should be automated.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Stakeholders should always be made aware of the implications of their requests (functionality-wise, schedule-wise, etc)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Stakeholder Corollary: Stakeholders will not always know what they truly want without developer feedback.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;&lt;strong&gt;Development / Production Stages&lt;/strong&gt;&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Experimentation&lt;/li&gt;
		&lt;li&gt;Incubation&lt;/li&gt;
		&lt;li&gt;Rapid-growth (agile development)&lt;/li&gt;
		&lt;li&gt;Quality-assurance&lt;/li&gt;
		&lt;li&gt;Maturation&lt;/li&gt;
		&lt;li&gt;Sustainable++&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;&lt;strong&gt;Absolute Bare Minimum a Developer Needs to Get Started&lt;/strong&gt;&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;A version control login and &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;How to Checkout the Source&lt;/li&gt;
		&lt;li&gt;How to Setup the Development Environment&lt;/li&gt;
		&lt;li&gt;How to Setup the Build Environment&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;&lt;strong&gt;Absolute Bare Minimum Deployment Documentation&lt;/strong&gt;&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;How to Setup the Deployment Environment&lt;/li&gt;
		&lt;li&gt;How to Deploy the Application&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;GTD&lt;/span&gt;++ Tools&lt;/p&gt;


	&lt;p&gt;Cross-platform&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Subversion&lt;/li&gt;
		&lt;li&gt;Trac&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Java&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Ant&lt;/li&gt;
		&lt;li&gt;JUnit&lt;/li&gt;
		&lt;li&gt;Javadoc&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;.NET&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;NAnt&lt;/li&gt;
		&lt;li&gt;NUnit&lt;/li&gt;
		&lt;li&gt;NDoc&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Ruby&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Rake&lt;/li&gt;
		&lt;li&gt;Test::Unit&lt;/li&gt;
		&lt;li&gt;RDoc&lt;/li&gt;
		&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;WATIR&lt;/span&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Python&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;SCons&lt;/li&gt;
		&lt;li&gt;PyUnit&lt;/li&gt;
		&lt;li&gt;pydoc&lt;/li&gt;
	&lt;/ul&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-06-15:288</id>
    <published>2008-06-15T02:00:00Z</published>
    <updated>2008-06-15T02:01:28Z</updated>
    <link href="http://shanti.railsblog.com/wildcard-subdomains-in-nginx" rel="alternate" type="text/html"/>
    <title>Wildcard Subdomains in nginx</title>
<content type="html">
            &amp;lt;center&gt;&lt;img src=&quot;http://incredimazing.com/static/media/2008/06/13/71d46d8045ea28e/thumbnail_lg.jpg&quot; /&gt;&amp;lt;/center&gt;

	&lt;p&gt;The mission: redirect a page &lt;a href=&quot;http://www.incredimazing.com/page/Scarlett_Jo&quot;&gt;like this&lt;/a&gt; (note the www in &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;) to &lt;a href=&quot;http://incredimazing.com/page/Scarlett_Jo&quot;&gt;this&lt;/a&gt; (look ma, no www!).&lt;/p&gt;


	&lt;p&gt;I&#8217;m using nginx&#8217;s handy vhosts feature.  This is the pertinent part of the new config file:&lt;/p&gt;


&lt;pre&gt;
server_name  .incredimazing.com;

# 301 redirect 'www.incredimazing.com' =&amp;gt; 'incredimazing.com'
#  Also works with:  'www.incredimazing.com/Foo_Bar' =&amp;gt; 'incredimazing.com/Foo_Bar'
if ($host = 'www.incredimazing.com') {
  rewrite ^/(.*)$ http://incredimazing.com/$1 permanent;
}
&lt;/pre&gt;

	&lt;p&gt;By setting the server name to &#8217;.incredimazing.com&#8217; this makes it so that &#8216;foo.incredimazing.com&#8217;, etc. will also get served by the same mongrels.&lt;/p&gt;


	&lt;p&gt;Handy if you give users their own subdomain, e.g. &lt;a href=&quot;http://alexis.incredimazing.com/&quot;&gt;alexis.incredimazing.com&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-06-02:286</id>
    <published>2008-06-02T00:26:00Z</published>
    <updated>2008-06-02T00:26:23Z</updated>
    <link href="http://shanti.railsblog.com/new-backup_fu-rails-plugin-maintainer" rel="alternate" type="text/html"/>
    <title>New backup_fu Rails Plugin Maintainer</title>
<content type="html">
            &lt;p&gt;Jonathan Vaught is the new maintainer of the &lt;a href=&quot;http://shanti.railsblog.com/backup-fu-makes-amazon-s3-backups-redonkulous&quot;&gt;backup_fu plugin&lt;/a&gt; that makes Amazon S3 backups &#8220;redonkulous&#8221; (I crack myself up sometimes).&lt;/p&gt;


	&lt;p&gt;You can checkout its new home over on GitHub at:&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://github.com/gravelpup/backup_fu&quot;&gt;http://github.com/gravelpup/backup_fu&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;thanks, Jonathan!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-05-15:280</id>
    <published>2008-05-15T16:31:00Z</published>
    <updated>2008-05-15T16:32:31Z</updated>
    <link href="http://shanti.railsblog.com/excessive-ferret-disk-usage" rel="alternate" type="text/html"/>
    <title>Excessive Ferret Disk Usage</title>
<content type="html">
            &lt;p&gt;I&#8217;m a big fan of &lt;a href=&quot;http://ferret.davebalmain.com/&quot;&gt;Ferret&lt;/a&gt; as a low-headache, low barrier to entry search/indexing utility for Rails apps.&lt;/p&gt;


	&lt;p&gt;Recently though one of my servers kept seeing its disk usage spike to 100% unexplicably.  I checked the usual suspects, log/ and tmp/ and found nothing.&lt;/p&gt;


	&lt;p&gt;Clueless, I reached out for a lil help from the pros.  Hat tip &lt;a href=&quot;http://blog.methodmissing.com/&quot;&gt;Lourens&lt;/a&gt; for suggesting Ferret as a possible culprit.&lt;/p&gt;


	&lt;p&gt;When I nuked the index/ dir for the site &lt;a href=&quot;http://ummyeah.com&quot;&gt;UmmYeah&lt;/a&gt;&#8212;disk usage dropped from 100% to 33%!  Woot.&lt;/p&gt;


	&lt;p&gt;... currently rebuilding the Ferret index.  Let&#8217;s hope, when rebuilt from scratch, the bad boy is much more compact.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-03-24:198</id>
    <published>2008-03-24T02:58:00Z</published>
    <updated>2008-05-15T16:27:12Z</updated>
    <link href="http://shanti.railsblog.com/7-mongrels-serve-920-000-pageviews-in-a-day" rel="alternate" type="text/html"/>
    <title>7 Mongrels Serve 920,000 Pageviews in a Day</title>
<content type="html">
            &amp;lt;center&gt;&lt;img src=&quot;http://img.skitch.com/20080310-fn8h9fwfhm5hernahm9aun251w.jpg&quot; alt=&quot;Summary (Incredimazing)&quot; /&gt;&amp;lt;/center&gt;

	&lt;p&gt;The site is &lt;a href=&quot;http://incredimazing.com&quot;&gt;Incredimazing&lt;/a&gt; (one of my pet projects) and the main page which attracted the web&#8217;s attention was &lt;a href=&quot;http://incredimazing.com/page/Earth_at_Night-686&quot;&gt;Earth at Night&lt;/a&gt; (cool, eh).&lt;/p&gt;


	&lt;p&gt;This time the traffic came from &lt;a href=&quot;http://www.fark.com/&quot;&gt;Fark&lt;/a&gt;, &lt;a href=&quot;http://reddit.com/&quot;&gt;reddit&lt;/a&gt; and various other sources.&lt;/p&gt;


	&lt;p&gt;This averages out to about 10.6 requests / second, but the traffic was very bursty&#8212;probably 600-700k of the pageviews came within a span of 4-5 hours when first hitting fark/reddit/etc.&lt;/p&gt;


	&lt;p&gt;Note: the complete setup that runs incredimazing + a bevy of other sites runs about $400.  If &lt;a href=&quot;http://shanti.railsblog.com/550k-pageviews-in-perspective&quot;&gt;my math from this post&lt;/a&gt; were to hold true, it would mean hardware costs for a site such as this could be as little as 0.5% (half a percent).  &lt;i&gt;But&#8230; but&#8230; rails doesn&#8217;t scale!&lt;/i&gt; :P&lt;/p&gt;


	&lt;p&gt;&lt;i&gt;Btw &#8211; this post is an update to &lt;a href=&quot;http://shanti.railsblog.com/how-7-mongrels-handled-a-550k-pageview-digging/&quot;&gt;this article&lt;/a&gt; which covered the initial digging.&lt;/i&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-03-16:184</id>
    <published>2008-03-16T14:09:00Z</published>
    <updated>2008-07-08T16:47:07Z</updated>
    <link href="http://shanti.railsblog.com/backup_fu-tip-clear-out-rails_root-tmp-backup" rel="alternate" type="text/html"/>
    <title>Backup_fu Tip: Clear out RAILS_ROOT/tmp/backup Periodically</title>
<content type="html">
            &lt;p&gt;Nothing&#8217;s ever safe and stable on the &#8216;net. You can have the most expensive servers money can buy, the best &lt;a href=&quot;http://broadband.o2.co.uk/&quot;&gt;broadband&lt;/a&gt; service on the &#8216;net, and the most high-end computer in the market but your system is still prone to crashes. That&#8217;s why a good knowledge on making backups is a must.&lt;/p&gt;


	&lt;p&gt;Just a tip, because I&#8217;ve finally bumped into an issue with this on one of my servers.&lt;/p&gt;


	&lt;p&gt;Backup_fu first dumps files to &lt;span class=&quot;caps&quot;&gt;RAILS&lt;/span&gt;_ROOT/tmp/backup.  This is nice and all to have a local copy of the backup &#8230; but it never does any cleaning out.&lt;/p&gt;


	&lt;p&gt;If you are looking for a solution that handles cleaning up old backups, I believe you can Google around and there are some out there like that.&lt;/p&gt;


	&lt;p&gt;What I will probably do going forward is create a reminder for myself via &lt;a href=&quot;http://backpackit.com&quot;&gt;Backpack&lt;/a&gt; or iCal each month to A) check on the backups in Amazon S3, and B) clean out tmp/backup in the rails apps, especially ones where the backups push 1, 2, 3 gigs a pop.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-02-20:154</id>
    <published>2008-02-20T10:21:00Z</published>
    <updated>2008-02-20T10:23:07Z</updated>
    <link href="http://shanti.railsblog.com/how-to-handle-facebook-app-uninstalls-with-rfacebook" rel="alternate" type="text/html"/>
    <title>How to Handle Facebook App Uninstalls with RFacebook</title>
<content type="html">
            &lt;p&gt;I posted the following &lt;a href=&quot;http://wiki.developers.facebook.com/index.php/Post-Remove_URL&quot;&gt;here&lt;/a&gt;&#8212;but thought I&#8217;d solicit other feedback via blog as well.&lt;/p&gt;


	&lt;p&gt;As of this writing, the rfacebook plugin does not seem to provide a way to handle uninstalls (easily).&lt;/p&gt;


	&lt;p&gt;Is there a method I&#8217;m not aware of?  Or does one handle it pretty much how I&#8217;ve done below?&lt;/p&gt;


	&lt;p&gt;In this example, to handle uninstalls in your rails app we will use the post-remove &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; of &#8216;foo.yourapp.com/uninstalled&#8217;.&lt;/p&gt;


	&lt;p&gt;In your application.rb, you probably have something like:&lt;/p&gt;


&lt;pre&gt;
  before_filter :require_facebook_install
  before_filter :require_facebook_login
&lt;/pre&gt;

	&lt;p&gt;Change your application.rb to something like:&lt;/p&gt;


&lt;pre&gt;
  before_filter :require_facebook_install, :except =&amp;gt; [:uninstalled]
  before_filter :require_facebook_login, :except =&amp;gt; [:uninstalled]

  # Before Filter on *only* the 'uninstalled' method
  before_filter :verify_uninstall_signature, :only =&amp;gt; [:uninstalled]

  # Note: it's important this method is *above* the 'protected' definition, since it needs to be called directly
  def uninstalled
    @fb_uid = params[:fb_sig_user]
    # From here on it will be app specific -- given the facebook uid, destroy the user, like...
    @user = User.find_by_fb_uid(@fb_uid)
    @user.destroy if @user
    render :nothing =&amp;gt; true; return
  end

  protected
   ...

&lt;/pre&gt;

	&lt;p&gt;Next, in your &#8216;protected&#8217; section, add the following method which roughly corresponds to the &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; / pseudocode:&lt;/p&gt;


&lt;pre&gt;
  def verify_uninstall_signature
    signature = ''
    keys = params.keys.sort
    keys.each do |key|
      next if key == 'fb_sig'
      next unless key.include?('fb_sig')
      key_name = key.gsub('fb_sig_', '')
      signature += key_name
      signature += '='
      signature += params[key]
    end
    signature += FACEBOOK['secret']
    calculated_sig = Digest::MD5.hexdigest(signature)
    #logger.info &quot;\nUNINSTALL :: Signature (fb_sig param from facebook) :: #{params[:fb_sig]}&quot; 
    #logger.info &quot;\nUNINSTALL :: Signature String (pre-hash) :: #{signature}&quot; 
    #logger.info &quot;\nUNINSTALL :: MD5 Hashed Sig :: #{calculated_sig}&quot; 
    if calculated_sig != params[:fb_sig]
      #logger.warn &quot;\n\nUNINSTALL :: WARNING :: expected signatures did not match\n\n&quot; 
      return false
    else
      #logger.warn &quot;\n\nUNINSTALL :: SUCCESS!! Signatures matched.\n&quot; 
    end
    return true
  end
&lt;/pre&gt;

	&lt;p&gt;This might be handy to add to &#8216;rfacebook&#8217;, but it sounds like &lt;a href=&quot;http://www.livelearncode.com/archives/30&quot;&gt;the state of that project&lt;/a&gt; is in flux.&lt;/p&gt;


	&lt;p&gt;Also, you might have to add this entry to your config/routes.rb file:&lt;/p&gt;


&lt;pre&gt;
  map.connect 'uninstalled', :controller =&amp;gt; 'application', :action =&amp;gt; 'uninstalled'
&lt;/pre&gt;

	&lt;p&gt;Happy uninstalling! :)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-02-18:147</id>
    <published>2008-02-18T14:07:00Z</published>
    <updated>2008-02-19T05:40:49Z</updated>
    <link href="http://shanti.railsblog.com/a-few-updates-to-backup_fu" rel="alternate" type="text/html"/>
    <title>A few updates to backup_fu</title>
<content type="html">
            &lt;p&gt;I&#8217;d like to give a special thanks to those who &lt;a href=&quot;http://shanti.railsblog.com/backup-fu-makes-amazon-s3-backups-redonkulous&quot;&gt;commented on the release of backup_fu&lt;/a&gt;&#8212;especially for all of the positive feedback.&lt;/p&gt;


	&lt;p&gt;In this release, the following features were added:&lt;/p&gt;


	&lt;pre&gt;&lt;code&gt;- PostgreSQL dump support
- Ability to supply your own custom MySQL dump options (config key 'mysqldump_options')
- Backup_fu now checks your ENV variables for AMAZON_ACCESS_KEY_ID and AMAZON_SECRET_ACCESS_KEY;  if found, it uses these instead of requiring them in config/backup_fu.yml.&lt;/code&gt;&lt;/pre&gt;


	&lt;p&gt;Since this is a minor release, there&#8217;s probably no need to update if you&#8217;ve already got v1.0 working like a charm.&lt;/p&gt;


	&lt;p&gt;For those who haven&#8217;t played with backup_fu, &lt;a href=&quot;http://shanti.railsblog.com/backup-fu-makes-amazon-s3-backups-redonkulous&quot;&gt;click here&lt;/a&gt; for the full scoop.&lt;/p&gt;


	&lt;p&gt;Thanks also to &lt;a href=&quot;http://info-architects.net/&quot;&gt;Toby Hede&lt;/a&gt; and &lt;a href=&quot;http://www.mrchucho.net/&quot;&gt;Ralph Churchill&lt;/a&gt; for submitting patches.&lt;/p&gt;


	&lt;p&gt;Toby&#8217;s added the ability to support user-supplied mysqldump options; Ralph&#8217;s for PostgreSQL dump support.&lt;/p&gt;


	&lt;p&gt;Also hat tip to &lt;a href=&quot;http://lemurheavy.com/&quot;&gt;nick&lt;/a&gt; for suggesting the &lt;span class=&quot;caps&quot;&gt;ENV&lt;/span&gt; variable support.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-02-18:146</id>
    <published>2008-02-18T13:19:00Z</published>
    <updated>2008-02-18T13:20:13Z</updated>
    <link href="http://shanti.railsblog.com/monkey-patching-activerecord-so-logger-works-seamlessly" rel="alternate" type="text/html"/>
    <title>Monkeypatching ActiveRecord so 'logger' Works Seamlessly</title>
<content type="html">
            &lt;p&gt;Ever tried calling &#8220;logger.info&#8221; from an ActiveRecord object, only to have rails lay the smack-down on ya?&lt;/p&gt;


	&lt;p&gt;Use &#8216;logger&#8217; seamlessly throughout your app with this monkey patch:&lt;/p&gt;


&lt;pre&gt;
module ActiveRecordExtensions

  def logger
    RAILS_DEFAULT_LOGGER
  end

end

class ActiveRecord::Base
  include ActiveRecordExtensions
end
&lt;/pre&gt;

	&lt;p&gt;Throw that in environment.rb or wherever you keep your monkey patches, and let the good times roll.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-02-18:144</id>
    <published>2008-02-18T07:43:00Z</published>
    <updated>2008-02-18T07:48:59Z</updated>
    <link href="http://shanti.railsblog.com/tinkering-with-git-quick-facebook-app-template" rel="alternate" type="text/html"/>
    <title>Tinkering with Git + Quick Facebook App Template</title>
<content type="html">
            &lt;p&gt;I just got my new &lt;a href=&quot;http://github.com/&quot;&gt;GitHub account&lt;/a&gt; &#8211; yay!&lt;/p&gt;


	&lt;p&gt;Time to tinker.  One thing I&#8217;ve done with rails is create a &#8220;QuickStart Rails&#8221; template that I have checked into svn.  It&#8217;s got several useful plugins that I use in just about all my rails apps, plus a working authentication system including all the boring, trivial details that come with that like &#8216;Forgot Password?&#8217; functionality, etc.&lt;/p&gt;


	&lt;p&gt;Not all apps get the QuickStart rails treatment, but if they involve user authentication, I usually bootstrap the app using QS.&lt;/p&gt;


	&lt;p&gt;Recently I&#8217;ve been working on a Facebook app; following its development, I&#8217;ve made a Quick FB rails application template.&lt;/p&gt;


	&lt;p&gt;Again, this does all of the mundane things that all Facebook apps will require, like an Invitation page:&lt;/p&gt;


&lt;div class=&quot;thumbnail&quot;&gt;&lt;a href=&quot;http://skitch.com/sbraford/gphc/facebook-maven-development&quot;&gt;&lt;img src=&quot;http://img.skitch.com/20080218-cb6ktx2fsrpp2udaamduwnam7q.preview.jpg&quot; alt=&quot;Facebook | Maven (Development)&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

	&lt;p&gt;&lt;br /&gt;&lt;/p&gt;


	&lt;p&gt;If you&#8217;re interested, you can &lt;a href=&quot;http://github.com/sbraford/quick-fb/tree/master&quot;&gt;browse the git repository&lt;/a&gt; online.&lt;/p&gt;


	&lt;p&gt;To bootstrap a new Quick FB app (&#8220;fb_foo&#8221;) using git, do a:&lt;/p&gt;


&lt;pre&gt;git clone git://github.com/sbraford/quick-fb.git fb_foo&lt;/pre&gt;

	&lt;p&gt;This will give you a complete Rails 2.0 application structure, plus:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;rfacebook, will_paginate plugins already added&lt;/li&gt;
		&lt;li&gt;application.rb configured for you&lt;/li&gt;
		&lt;li&gt;User, Friendship models already created&#8212;as users add the application, they are automatically associated as Friends within your app&lt;/li&gt;
		&lt;li&gt;Invitation widget (like shown above) already included&lt;/li&gt;
	&lt;/ul&gt;


See config/environment.rb for the list of TODOs once you have cloned the Quick FB git repo:
&lt;pre&gt;

TODO after cloning the quick-fb git repo:

  1. Create your app's database.  Modify 'config/database.yml'.

  2. Open 'config/facebook.yml' and modify the following:

      key: YOUR_API_KEY_HERE
      secret: YOUR_API_SECRET_HERE
      canvas_path: /yourAppName/
      callback_path: /relative_root/
      sever_host: foo.com
      app_name: Foo App

  3. Modify the relative URL root below.

  4. Open up 'app/helpers/application_helper.rb' and modify the invitation text.

  5. Generate a new secret app key with:

        rake secret

  Copy &#38; paste this into the session config section above. (this might not be necessary for fb apps, but just in case)
&lt;/pre&gt;

	&lt;p&gt;Note: to port this over to &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt;, I believe you can simply do a:&lt;/p&gt;


&lt;pre&gt;
  rm -rf .git/
  rm .gitignore  # and any other .gitignore files

&lt;/pre&gt;

	&lt;p&gt;... and you should be good to go. (copy to an existing svn repo and svn add/import as usual)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-02-07:137</id>
    <published>2008-02-07T12:37:00Z</published>
    <updated>2008-05-15T16:27:29Z</updated>
    <link href="http://shanti.railsblog.com/backup-fu-makes-amazon-s3-backups-redonkulous" rel="alternate" type="text/html"/>
    <title>backup_fu Makes Amazon S3 Backups Redonkulous</title>
<content type="html">
            &lt;p&gt;&lt;img src=&quot;http://shanti.railsblog.com/assets/2008/2/7/backup_fu2.png&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Redonkulously easy, that is.&lt;/p&gt;


	&lt;p&gt;Your rails app has been humming along nicely for several months, then suddenly it hits you, &lt;i&gt;wait, are we backing up our database / uploaded files yet?&lt;/i&gt;&lt;/p&gt;


	&lt;p&gt;Well, of course &lt;i&gt;you&lt;/i&gt; are.  But for those who prefer to live on the edge, launching an app without a well-articulated backup strategy, I give you &lt;i&gt;backup_fu&lt;/i&gt;.&lt;/p&gt;


	&lt;p&gt;It&#8217;s a rails plugin, invoked via rake tasks.  After installing the plugin and modifying a few lines in a config file, you can have your application backing up both its database &lt;b&gt;and&lt;/b&gt; static files to &lt;a href=&quot;http://aws.amazon.com/s3&quot;&gt;Amazon S3&lt;/a&gt; within minutes.&lt;/p&gt;


	&lt;p&gt;&lt;small&gt;&lt;b&gt;Update&lt;/b&gt;: backup fu does now support PostgresSQL.  &lt;a href=&quot;http://shanti.railsblog.com/a-few-updates-to-backup_fu&quot;&gt;See this post&lt;/a&gt; for the 411.&lt;/small&gt;&lt;/p&gt;


	&lt;h2&gt;Installation&lt;/h2&gt;


	&lt;p&gt;Grab the only dependency, the aws-s3 gem (if not installed already):&lt;/p&gt;


&lt;pre&gt;
sudo gem install aws-s3
&lt;/pre&gt;

	&lt;p&gt;And the plugin:&lt;/p&gt;


&lt;pre&gt;
ruby script/plugin install http://backup-fu.googlecode.com/svn/backup_fu/
&lt;/pre&gt;

	&lt;h2&gt;Configuration&lt;/h2&gt;


	&lt;p&gt;Generate the default config/backup_fu.yml file with:&lt;/p&gt;


&lt;pre&gt;
rake backup_fu:setup
&lt;/pre&gt;

	&lt;p&gt;You&#8217;ll need to modify at least these four lines in config/backup_fu.yml:&lt;/p&gt;


&lt;pre&gt;
# The app_name is used as the backup filename prefix
app_name: replace_me
# Note: please create this bucket (whatever yours may be) externally first:
s3_bucket: some-s3-bucket
aws_access_key_id: --replace me with your AWS access key id--
aws_secret_access_key: --replace me with your AWS secret access key--
&lt;/pre&gt;

	&lt;p&gt;If you&#8217;re on &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt;, the excellent &lt;a href=&quot;http://people.no-distance.net/ol/software/s3/&quot;&gt;S3 Browser&lt;/a&gt; will have you creating S3 buckets, browsing them, and uploading/downloading to them within minutes.&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;https://jets3t.dev.java.net/&quot;&gt;Jets3t&lt;/a&gt; is a Java-based S3 browser and should do the trick on win32/etc systems.&lt;/p&gt;


	&lt;h2&gt;Basic Usage&lt;/h2&gt;


	&lt;p&gt;To dump your database (to &lt;span class=&quot;caps&quot;&gt;RAILS&lt;/span&gt;_ROOT/tmp/backup):&lt;/p&gt;


&lt;pre&gt;
rake backup_fu:dump
&lt;/pre&gt;

	&lt;p&gt;In production environments, of course, you may have to do something like:&lt;/p&gt;


&lt;pre&gt;
RAILS_ENV=production rake backup_fu:dump
&lt;/pre&gt;

	&lt;p&gt;To dump your database, then send the tar/gzipped copy to Amazon S3, it&#8217;s as simple as:&lt;/p&gt;


&lt;pre&gt;
rake backup
&lt;/pre&gt;

	&lt;p&gt;This will place a file named something like &#8216;foo_app_2008-02-07_db.tar.gz&#8217; into your Amazon S3 bucket (as specified by s3_bucket from your config file).&lt;/p&gt;


	&lt;h2&gt;Configuration Options&lt;/h2&gt;


	&lt;p&gt;If you bump into any snafus, the first thing you should do is enable verbosity via the config file:&lt;/p&gt;


&lt;pre&gt;
verbose: true
&lt;/pre&gt;

	&lt;p&gt;See &lt;code&gt;vendor/plugins/backup_fu/config/backup_fu.yml.advanced_example&lt;/code&gt; for the list of advanced configuration options. ( &lt;a href=&quot;http://backup-fu.googlecode.com/svn/backup_fu/config/backup_fu.yml.advanced_example&quot;&gt;view online&lt;/a&gt; )&lt;/p&gt;


	&lt;p&gt;The most common issue that one might run into is &#8216;mysqldump&#8217; not being in the user path.&lt;/p&gt;


	&lt;p&gt;To solve this do a &#8216;locate mysqldump&#8217; or otherwise find its absolute path, and specify it explicitly in config/backup_fu.yml:&lt;/p&gt;


&lt;pre&gt;
mysqldump_path: /usr/local/mysql/bin/mysqldump
&lt;/pre&gt;

	&lt;p&gt;Also see the &lt;a href=&quot;http://backup-fu.googlecode.com/svn/backup_fu/README&quot;&gt;&lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt;&lt;/a&gt; for more on debugging snafus and advanced configuration options.&lt;/p&gt;


	&lt;h2&gt;Static File Backups&lt;/h2&gt;


	&lt;p&gt;Backing up your database is great and all, but what if users upload files too?&lt;/p&gt;


	&lt;p&gt;Let&#8217;s say you&#8217;ve got a directory &lt;span class=&quot;caps&quot;&gt;RAILS&lt;/span&gt;_ROOT/public/static where all of these files reside.&lt;/p&gt;


	&lt;p&gt;In our fictional example, this directory is really a symlink to /apps/foo/static.  So we specify this as the &#8216;static_paths&#8217; key (again in config/backup_fu.yml):&lt;/p&gt;


&lt;pre&gt;
static_paths: &quot;/apps/foo/static&quot; 
&lt;/pre&gt;

	&lt;p&gt;Let&#8217;s say we also wanted to backup &#8221;/apps/foo/user_images&#8221;.&lt;/p&gt;


	&lt;p&gt;Multiple target static directories can be delimited via whitespace:&lt;/p&gt;


&lt;pre&gt;
static_paths: &quot;/apps/foo/static /apps/foo/user_images&quot; 
&lt;/pre&gt;

	&lt;p&gt;First let&#8217;s try dumping these static directories (with full contents) into a tar/gzipped archive in &lt;span class=&quot;caps&quot;&gt;RAILS&lt;/span&gt;_ROOT/tmp/backup:&lt;/p&gt;


&lt;pre&gt;
rake backup_fu:static:dump
&lt;/pre&gt;

	&lt;p&gt;If that worked, let&#8217;s go for the full enchilada (dumping + uploading to S3) with:&lt;/p&gt;


&lt;pre&gt;
rake backup_fu:static:backup
&lt;/pre&gt;

	&lt;p&gt;And for backing up both your database + static files (they will get uploaded as separate, distinct archives) in one rake command:&lt;/p&gt;


&lt;pre&gt;
rake backup_fu:all
&lt;/pre&gt;

	&lt;p&gt;Phew.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://shanti.railsblog.com/assets/2008/2/7/losing_data.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;h2&gt;Notes&lt;/h2&gt;


	&lt;p&gt;While I had trouble with aws-s3 in its early days, I&#8217;ve since used aws-s3 (and backup_fu) to send a 4GB file to Amazon S3.  &lt;small&gt;VPSes or systems with much less memory might have issues backing up such huge files, though.&lt;/small&gt;&lt;/p&gt;


	&lt;p&gt;See the &lt;a href=&quot;http://backup-fu.googlecode.com/svn/backup_fu/README&quot;&gt;&lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt;&lt;/a&gt; for cronjob examples.&lt;/p&gt;


	&lt;p&gt;Pluginizing this code (which existed for a while in my apps, though not as a plugin) was inspired by &lt;a href=&quot;http://spattendesign.com/&quot;&gt;Scott Patten&lt;/a&gt; who has written a similar kind of plugin.&lt;/p&gt;


	&lt;p&gt;Backup_fu does not erase old backup archives for you.  This is left as an exercise for the reader. :)  But seriously, it&#8217;s probably a good idea to check on your backups every month or so and do some pruning then, by hand if necessary.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-02-01:129</id>
    <published>2008-02-01T00:08:00Z</published>
    <updated>2008-02-01T00:13:01Z</updated>
    <link href="http://shanti.railsblog.com/how-to-install-imagemagick-from-source-on-os-x" rel="alternate" type="text/html"/>
    <title>How to Install ImageMagick from Source on OS X</title>
<content type="html">
            &lt;p&gt;&lt;img src=&quot;http://shanti.railsblog.com/assets/2008/2/1/ihasmagick.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;First grab the source:&lt;/p&gt;


&lt;pre&gt;
wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick.tar.gz
&lt;/pre&gt;

	&lt;p&gt;Unarchive it:&lt;/p&gt;


&lt;pre&gt;
tar xvzf ImageMagick.tar.gz
&lt;/pre&gt;

	&lt;p&gt;The old ./configure / make / sudo make install ritual:&lt;/p&gt;


&lt;pre&gt;
cd ImageMagick-6.3.8
# Or whichever the current version is, of course.
./configure
make
sudo make install
&lt;/pre&gt;

	&lt;p&gt;You should be good to go.  Lately I&#8217;ve been having luck with &lt;a href=&quot;http://rubyforge.org/projects/mini-magick/&quot;&gt;MiniMagick&lt;/a&gt; (all I need to do is crop/resize for this particular project).&lt;/p&gt;


	&lt;p&gt;Type this to make sure you can use ImageMagick from the command line at least:&lt;/p&gt;


&lt;pre&gt;
convert -version
&lt;/pre&gt;

	&lt;p&gt;I love that ruby (and many scripting languages) make it so easily to &#8220;shell out&#8221; to scripts (as minimagick does).  It really makes ruby performance alarmists look bad when shelling out to time-tested, battle-hardened C-based scripts is so easy, and works so well. (I&#8217;ve had success shelling out to the following in many apps: curl, imagemagick, wget, etc)&lt;/p&gt;


	&lt;h2&gt;How to Use MiniMagick in your Rails App&lt;/h2&gt;


	&lt;p&gt;Grab the gem:&lt;/p&gt;


&lt;pre&gt;
sudo gem install mini_magick
&lt;/pre&gt;

	&lt;p&gt;Drop this in your config/environment.rb:&lt;/p&gt;


&lt;pre&gt;
require 'rubygems'
gem 'mini_magick'
require 'mini_magick'
&lt;/pre&gt;

	&lt;p&gt;Example usage:&lt;/p&gt;


&lt;pre&gt;
class Pic &amp;lt; ActiveRecord::Base

  # Where size is a string like '90x90', '300x200', etc
  def create_perfect_thumbnail(size)

    image = MiniMagick::Image.from_file(self.pic_path)
    height, width = image['height'].to_f, image['width'].to_f

    # FIRST SHAVE off some of the image to make it square
    if width &amp;lt; height
      shave = ((height - width)/2).round
      image.shave(&quot;0x#{shave}&quot;)
    else
      shave = ((width - height)/2).round
      image.shave(&quot;#{shave}x0&quot;)
    end

    image.resize(size)
    image.write(self.pic_path(size))

    # I had issues on my linux box with the pic not being readable by the web server,
    #   following the resize.  Set permissions o+r to fix this.    
    if RAILS_ENV == 'production' # Set permissions to o+r
      `chmod o+r #{self.pic_path(size)}`
    end

  end

  def pic_path(size)
    # Just an example -- I normally group pics by user_id under a public static dir.
    File.join(RAILS_ROOT, 'public', 'static', &quot;#{size}_#{self.original_filename}&quot;) 
  end

end
&lt;/pre&gt;

	&lt;p&gt;That will shave off some of the pic, making a munged square from the original, before proceeding to make square thumbnails from that.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-01-27:122</id>
    <published>2008-01-27T21:19:00Z</published>
    <updated>2008-01-27T21:24:09Z</updated>
    <link href="http://shanti.railsblog.com/ruby-gets-a-reddit" rel="alternate" type="text/html"/>
    <title>Ruby gets a Reddit</title>
<content type="html">
            &lt;p&gt;&lt;a href=&quot;http://reddit.com&quot;&gt;Reddit&lt;/a&gt; and &lt;a href=&quot;http://programming.reddit.com&quot;&gt;programming.reddit.com&lt;/a&gt; are two of my favorite social news sites.&lt;/p&gt;


	&lt;p&gt;Now, courtesy of &lt;a href=&quot;http://jamesgolick.com/2008/1/25/ruby-reddit&quot;&gt;James Golick&lt;/a&gt; &#8211; they just opened &lt;a href=&quot;http://ruby.reddit.com&quot;&gt;ruby.reddit.com&lt;/a&gt; &#8211; sweet!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-01-27:121</id>
    <published>2008-01-27T19:08:00Z</published>
    <updated>2008-02-07T10:39:15Z</updated>
    <link href="http://shanti.railsblog.com/vps-link-outage-benchmarks" rel="alternate" type="text/html"/>
    <title>VPSLink Outage + Some Raw Server Benchmarks</title>
<content type="html">
            &lt;p&gt;Back up after a brief (20+ hour) outage which was triggered by upgrading the &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; where this blog is hosted.  More &lt;a href=&quot;http://sablog.com/archives/2008/01/26/vpslink-be-careful-when-upgrading&quot;&gt;details here&lt;/a&gt; for the curious.&lt;/p&gt;


	&lt;p&gt;After coming back online at full &lt;span class=&quot;caps&quot;&gt;CPU&lt;/span&gt; availability, I ran &lt;a href=&quot;http://members.dslextreme.com/users/andylee/unixbench-4.1.0-wht.tar.gz&quot;&gt;this benchmark script&lt;/a&gt; on the &lt;a href=&quot;http://vpslink.com/vps-hosting/&quot;&gt;Link 6&lt;/a&gt; vps:&lt;/p&gt;


&lt;pre&gt;
==============================================================
BYTE UNIX Benchmarks (Version 4.1-wht.1)
System -- Linux videolockr.com 2.6.18-ovz028stab039.1-smp #1 SMP Tue Jul 24 12:12:48 MSD 2007 i686 i686 i386 GNU/Linux
/dev/simfs            79691776   4390104  75301672   6% /

Start Benchmark Run: Sun Jan 27 10:21:44 PST 2008
 10:21:44 up 16:57,  1 user,  load average: 0.29, 0.06, 0.04

End Benchmark Run: Sun Jan 27 10:40:59 PST 2008
 10:40:59 up 17:16,  1 user,  load average: 16.21, 6.57, 3.22

                     INDEX VALUES            
TEST                                        BASELINE     RESULT      INDEX

Dhrystone 2 using register variables        376783.7  4076800.9      108.2
Double-Precision Whetstone                      83.1      949.2      114.2
Execl Throughput                               188.3     1613.2       85.7
File Copy 1024 bufsize 2000 maxblocks         2672.0   129719.0      485.5
File Copy 256 bufsize 500 maxblocks           1077.0    30195.0      280.4
File Read 4096 bufsize 8000 maxblocks        15382.0   490094.0      318.6
Pipe Throughput                             111814.6   688167.0       61.5
Pipe-based Context Switching                 15448.6   108170.3       70.0
Process Creation                               569.3     7265.2      127.6
Shell Scripts (8 concurrent)                    44.8      209.5       46.8
System Call Overhead                        114433.5   443236.3       38.7
                                                                 =========
     FINAL SCORE                                                     114.8
&lt;/pre&gt;

	&lt;p&gt;The &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; comes in at $129.95, which of course, one could have their own dedicated server for that amount.  VPSes are truly the crack rock of the hosting industry&#8212;the first few hits are cheap, but the addiction grows progressively more expensive as time passes. :)&lt;/p&gt;


	&lt;p&gt;What I like about VPSes: a new one can usually be provisioned within as little as 2 hours.  Also, a while back I had a string of hardware failures on dedicated boxes.  So far my VPSes are batting 1,000 when it comes to hardware success.&lt;/p&gt;


	&lt;p&gt;For comparison, here is a benchmark from a HiVelocity Small Business Server (both are Fedora Core, btw) which costs $83 / month.&lt;/p&gt;


&lt;pre&gt;
==============================================================
BYTE UNIX Benchmarks (Version 4.1-wht.1)
System -- Linux server.bradley.org 2.6.19-1.2288.fc5 #1 Sat Feb 10 14:52:17 EST 2007 i686 i686 i386 GNU/Linux
/dev/hda6              2030736    209076   1716840  11% /

Start Benchmark Run: Sun Mar 18 18:09:05 EDT 2007
 18:09:05 up  5:05,  1 user,  load average: 0.15, 0.03, 0.01

End Benchmark Run: Sun Mar 18 18:20:39 EDT 2007
 18:20:39 up  5:16,  1 user,  load average: 13.30, 5.84, 2.69

                     INDEX VALUES            
TEST                                        BASELINE     RESULT      INDEX

Dhrystone 2 using register variables        376783.7  3266804.6       86.7
Double-Precision Whetstone                      83.1      757.4       91.1
Execl Throughput                               188.3      999.2       53.1
File Copy 1024 bufsize 2000 maxblocks         2672.0    53928.0      201.8
File Copy 256 bufsize 500 maxblocks           1077.0    17294.0      160.6
File Read 4096 bufsize 8000 maxblocks        15382.0   248599.0      161.6
Pipe-based Context Switching                 15448.6    87610.7       56.7
Pipe Throughput                             111814.6   400521.9       35.8
Process Creation                               569.3     4119.4       72.4
Shell Scripts (8 concurrent)                    44.8      210.6       47.0
System Call Overhead                        114433.5   495582.9       43.3
                                                                 =========
     FINAL SCORE                                                      78.1
&lt;/pre&gt;

	&lt;p&gt;The server I believe is comparable to &lt;a href=&quot;http://www.hivelocity.net/Hosting/package.php?action=pack_details&#38;id=156&#38;gr=1&quot;&gt;something like this&lt;/a&gt; which is now $99 / mo.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://shanti.railsblog.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:shanti.railsblog.com,2008-01-26:115</id>
    <published>2008-01-26T08:55:00Z</published>
    <updated>2008-01-26T09:05:07Z</updated>
    <link href="http://shanti.railsblog.com/monitor-mysql-with-god" rel="alternate" type="text/html"/>
    <title>Monitor MySQL with God on Your Side</title>
<content type="html">
            &lt;p&gt;&lt;img src=&quot;http://shanti.railsblog.com/assets/2008/1/26/god.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://god.rubyforge.org/&quot;&gt;god&lt;/a&gt; is a great ruby-based alternative to &lt;a href=&quot;http://www.tildeslash.com/monit/&quot;&gt;monit&lt;/a&gt; and other process monitoring tools.  While I have had success with monit, I found its configuration syntax tedious.  Monit&#8217;s configuration syntax makes it painful to do things like decrease/increase the number of mongrels you are monitoring, etc.&lt;/p&gt;


	&lt;p&gt;Note: the following assumes we&#8217;re on some kind of Fedora Core (or similar) system.  Replace &#8221;/etc/init.d/mysql stop|start|restart&#8221; with however this is done in your distro.&lt;/p&gt;


Configuration is where god shines.  Let&#8217;s get started:
&lt;pre&gt;
sudo gem install god
&lt;/pre&gt;

	&lt;p&gt;In this tutorial, I will only be covering how to monitor your MySQL process using god.  The main &lt;a href=&quot;http://god.rubyforge.org/&quot;&gt;god website&lt;/a&gt; has an excellent tutorial on how to monitor your mongrels.&lt;/p&gt;


	&lt;p&gt;God works by monitoring pid files.  It has other functionality as well, but for MySQL 5.x monitoring, all we need is the location of the MySQL &lt;span class=&quot;caps&quot;&gt;PID&lt;/span&gt; file.  You can find this on your system with:&lt;/p&gt;


&lt;pre&gt;
locate .pid | grep mysql
&lt;/pre&gt;

	&lt;p&gt;On my system, the MySQL pid file was located at:&lt;/p&gt;


&lt;pre&gt;
/var/run/mysqld/mysqld.pid
&lt;/pre&gt;

	&lt;p&gt;Next we need to know how to stop/start/restart MySQL.  On most systems, this can simply be done with:&lt;/p&gt;


&lt;pre&gt;
cd /etc/init.d
sudo ./mysqld stop|start|restart
&lt;/pre&gt;

	&lt;p&gt;It&#8217;s a good idea to make sure these commands work by hand, of course, before assuming god should use them to manage MySQL.&lt;/p&gt;


	&lt;p&gt;Assuming your information matches the above, the following god config file should do the trick:&lt;/p&gt;


&lt;pre&gt;
# God config file.
#
# Documentation: http://god.rubyforge.org/
#
# run with:  god -c /root/monitor.god
#

God.watch do |w|
  w.name = 'mysql-process'
  w.group = 'mysql'
  w.interval = 30.seconds # default      
  w.start = &quot;cd /etc/init.d &#38;&#38; ./mysqld start&quot; 
  w.stop = &quot;cd /etc/init.d &#38;&#38; ./mysqld start&quot; 
  w.restart = &quot;cd /etc/init.d &#38;&#38; ./mysqld restart&quot; 
  w.start_grace = 10.seconds
  w.restart_grace = 10.seconds
  w.pid_file = '/var/run/mysqld/mysqld.pid'
  w.behavior(:clean_pid_file)

  w.start_if do |start|
    start.condition(:process_running) do |c|
      c.interval = 5.seconds
      c.running = false
    end
  end

  # lifecycle
  w.lifecycle do |on|
    on.condition(:flapping) do |c|
      c.to_state = [:start, :restart]
      c.times = 5
      c.within = 5.minute
      c.transition = :unmonitored
      c.retry_in = 10.minutes
      c.retry_times = 5
      c.retry_within = 2.hours
    end
  end
end
&lt;/pre&gt;

	&lt;p&gt;Place this into a file located at &#8217;/root/monitor.god&#8217;.  (for the below examples to work)&lt;/p&gt;


	&lt;p&gt;In order to test god, kick it into non-daemonized mode with:&lt;/p&gt;


&lt;pre&gt;
sudo god -c /root/monitor.god -D
&lt;/pre&gt;

	&lt;p&gt;You should see some output like:&lt;/p&gt;


&lt;pre&gt;
I, [2008-01-26 00:30:05 #1841]  INFO -- : Started on drbunix:///tmp/god.17165.sock
I, [2008-01-26 00:30:05 #1841]  INFO -- : mysql-process move 'unmonitored' to 'up'
I, [2008-01-26 00:30:06 #1841]  INFO -- : mysql-process [ok] process is running (ProcessRunning)
&lt;/pre&gt;

	&lt;p&gt;In another terminal, stop MySQL by hand:&lt;/p&gt;


&lt;pre&gt;
cd /etc/init.d
sudo ./mysqld stop
&lt;/pre&gt;

	&lt;p&gt;This may not replicate exactly what happens when MySQL goes down in the wild, but at least you can test god&#8217;s basic functionality.&lt;/p&gt;


	&lt;p&gt;You should see the command line output of god indicate that it is restarting MySQL:&lt;/p&gt;


&lt;pre&gt;
I, [2008-01-26 00:46:01 #18173]  INFO -- : mysql-process [trigger] mysql-process God::Conditions::ProcessRunning: no such pid file: /var/run/mysqld/mysqld.pid (ProcessRunning)
I, [2008-01-26 00:46:01 #18173]  INFO -- : mysql-process move 'up' to 'start'
I, [2008-01-26 00:46:01 #18173]  INFO -- : mysql-process before_start: no pid file to delete (CleanPidFile)
I, [2008-01-26 00:46:01 #18173]  INFO -- : mysql-process start: cd /etc/init.d &#38;&#38; ./mysqld start
I, [2008-01-26 00:46:12 #18173]  INFO -- : mysql-process [ok] process is running (ProcessRunning)
&lt;/pre&gt;

	&lt;p&gt;Next up, you can daemonize god with:&lt;/p&gt;


&lt;pre&gt;
sudo god -c /root/monitor.god
&lt;/pre&gt;

	&lt;p&gt;Now check if MySQL is up:&lt;/p&gt;


&lt;pre&gt;
sudo god status mysql
&lt;/pre&gt;

	&lt;p&gt;Tail the god&#8217;s MySQL status log with:&lt;/p&gt;


&lt;pre&gt;
sudo god log mysql
&lt;/pre&gt;

To add this as a @reboot cronjob, so that god always starts on reboot:
&lt;pre&gt;
# First su to root:
su
# Edit root's crontab:
crontab -e
&lt;/pre&gt;

Then paste this entry into root&#8217;s crontab and save:
&lt;pre&gt;
@reboot /usr/bin/god -c /root/monitor.god
&lt;/pre&gt;

	&lt;p&gt;Of course, execute &#8216;ps aux | grep god&#8217; to do a sanity check that the above is the same on your system as well.  (while god is running)&lt;/p&gt;


	&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;BTW&lt;/span&gt; &#8211; I get this warning when starting god, but everything still appears to work fine for me:&lt;/p&gt;


&lt;pre&gt;
***********************************************************************
*
* Event conditions are not available for your installation of god.
* You may still use and write custom conditions using the poll system
*
***********************************************************************
&lt;/pre&gt;

	&lt;p&gt;My next question:  what program does one use to monitor god itself?&lt;/p&gt;
          </content>  </entry>
</feed>
