<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Nate Wiger vs Software</title>
	<atom:link href="http://nateware.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://nateware.com</link>
	<description>...or how many beers until the servers work?</description>
	<lastBuildDate>Tue, 19 Apr 2011 18:21:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='nateware.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Nate Wiger vs Software</title>
		<link>http://nateware.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://nateware.com/osd.xml" title="Nate Wiger vs Software" />
	<atom:link rel='hub' href='http://nateware.com/?pushpress=hub'/>
		<item>
		<title>Controlling What You Can</title>
		<link>http://nateware.com/2011/02/10/controlling-what-you-can/</link>
		<comments>http://nateware.com/2011/02/10/controlling-what-you-can/#comments</comments>
		<pubDate>Thu, 10 Feb 2011 18:59:07 +0000</pubDate>
		<dc:creator>Nate Wiger</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://nateware.com/?p=122</guid>
		<description><![CDATA[Yesterday, my good friends up at United Front Games had their game True Crime cancelled by Activision. My team worked closely with United Front on ModNation Racers, so I know firsthand that UFG is a standup studio of hardworking guys and gals. There&#8217;s much that this caused me to reflect on, especially in regards to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nateware.com&amp;blog=12799998&amp;post=122&amp;subd=nateware&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Yesterday, my good friends up at <a href="http://www.unitedfrontgames.com/">United Front Games</a> had their game True Crime <a href="http://zoknowsgaming.com/2011/02/09/true-crime-hong-kong-canceled/">cancelled by Activision</a>.   My team worked closely with United Front on <a href="http://community.modnation.com/en-us">ModNation Racers</a>, so I know firsthand that UFG is a standup studio of hardworking guys and gals.</p>
<p>There&#8217;s much that this caused me to reflect on, especially in regards to the gaming industry as a whole.  With the prevalence of $0.99 iPhone games and free Facebook games, is the market going to continue to be there for $60 premium experiences?  Will gaming go the way of movies, where there are low-budget indie films, nothing in the middle, and then multi-multi-million Transformers/Inception spectacles?  Or will we end up like the music business, where everyone is just fine with poor-quality MP3&#8242;s since the price is right?</p>
<p>Who knows &#8211; my crystal ball is in the shop.  Which brings me to the title of this post.  You can only do the best you can, with the time you have, roll the bones, and hope for the best.</p>
<p>All of us tend to worry about things that are out of our control.  We worry about plane crashes, floods, economic collapse &#8211; the list goes on.  In fact, things outside of our control often cause the most stress, as they can make us feel powerless.</p>
<p>But when it comes to shipping a product (and retaining your sanity), all you can do is focus as much time and energy as possible on your areas of responsibility, and make sure that your deliverables are as awesome as possible.  If you&#8217;re an online programmer, worrying about the character animation being good enough is just going to stress you out, and take valuable time away from all the online programmery things you need to do.</p>
<p>This doesn&#8217;t mean you should put blinders on and get tunnel vision.  But there are times for offering your peers feedback on a product as a whole, and times for putting your head down and knocking out features.  To me, this dovetails with the classic &#8220;glass house&#8221; proverb.  Once your features are all nice and shiny, then by all means offer feedback to others.  But if you still have work to do, you need to knock that out first.  (Hint: Your team members feel the same way.  Nobody likes criticism from somebody who can&#8217;t get his <i>own</i> act together.)</p>
<p>So bringing it back around:</p>
<ol>
<li>Worry about your personal deliverables first</li>
<li>Then worry about your team&#8217;s deliverables</li>
<li>Then worry about the product as a whole</li>
<li>Then worry about whether it will sell in Southeast Asia</li>
<li>Then worry about global warming</li>
</ol>
<p>Your sanity (and your product) will thank you.</p>
<p>And again, good vibes up to my friends at UFG.  I know you put your heart and soul into &#8220;True Crime: Hong Kong&#8221;, and that&#8217;s the best you can do.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nateware.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nateware.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nateware.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nateware.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nateware.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nateware.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nateware.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nateware.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nateware.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nateware.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nateware.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nateware.wordpress.com/122/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nateware.wordpress.com/122/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nateware.wordpress.com/122/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nateware.com&amp;blog=12799998&amp;post=122&amp;subd=nateware&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nateware.com/2011/02/10/controlling-what-you-can/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/69f4b9b411dfcaebe01d0fde8c751726?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nwiger</media:title>
		</media:content>
	</item>
		<item>
		<title>Atomic Rant Redux</title>
		<link>http://nateware.com/2010/06/14/atomic-rant-redux/</link>
		<comments>http://nateware.com/2010/06/14/atomic-rant-redux/#comments</comments>
		<pubDate>Tue, 15 Jun 2010 02:38:07 +0000</pubDate>
		<dc:creator>Nate Wiger</dc:creator>
				<category><![CDATA[Techie Bits]]></category>

		<guid isPermaLink="false">http://nateware.com/?p=67</guid>
		<description><![CDATA[My atomic rant has gotten a ton of traffic &#8211; more than I forsaw.  Seems atomicity is a hot topic in the web world these days. My guess is increasing user concurrency, coupled with more interactive apps, exposes all sorts of edge cases. Throw in some horizontal scaling/sharding and it gets really nasty really quickly. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nateware.com&amp;blog=12799998&amp;post=67&amp;subd=nateware&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>My <a href="http://nateware.com/2010/02/18/an-atomic-rant/">atomic rant</a> has gotten a ton of traffic &#8211; more than I forsaw.  Seems atomicity is a hot topic in the web world these days.  My guess is increasing user concurrency, coupled with more interactive apps, exposes all sorts of edge cases.  Throw in some horizontal scaling/sharding and it gets really nasty really quickly.</p>
<p>I wanted to write a follow-up post to step back and look at a few more high-level concerns with atomicity, as well as some Redis-specific issues we&#8217;ve seen.</p>
<h2>Know Your Actors</h2>
<p><img class="alignright size-medium wp-image-72" title="The most amazing actors EVER" src="http://nateware.files.wordpress.com/2010/07/new-moon-official-cast.jpg?w=300&#038;h=190" alt="The most amazing actors EVER" width="300" height="190" />In my <a href="http://nateware.com/2010/02/18/an-atomic-rant/">original rant</a>, I used the example of students enrolling in online classes to illustrate why atomicity was crucial to operations with multiple actors. And speaking of actors, they&#8217;re an even better <span style="text-decoration:line-through;">target</span> analogy.  You need to assume your actors are all going to try to jam through the audition door at the same time.  What happens if they are all talking to the director at once?  How many conversations can continue in parallel?  If you&#8217;re careful, you can get away with one final gate at the end, which makes your life infinitely easier.  That is, funnel everyone to a decision point, congratulate one person, then tell the others sorry.</p>
<p>Of course, if that funnel is too long, you&#8217;re going to piss off your users in a major way.  <a href="http://nateware.files.wordpress.com/2010/07/beerbongs.jpg"><img src="http://nateware.files.wordpress.com/2010/07/beerbongs.jpg?w=91&#038;h=150" alt="Long long funnel" title="No I don&#039;t know these people - really" width="91" height="150" class="alignleft size-thumbnail wp-image-98" /></a>If you&#8217;ve ever bought tickets from Ticketmaster, you&#8217;re familiar with this problem.  Granted they&#8217;ve gotten much better over the years (which is saying something&#8230;), and this is partially due to embracing the Amazon <a href="http://blogs.msdn.com/b/pathelland/archive/2007/05/15/memories-guesses-and-apologies.aspx">guesses and apologies approach</a>.  If you have 200 tickets left, a person can probably get one.  But if you have 10 tickets left, they&#8217;re probably going to get screwed.  If you can help with the user&#8217;s expectations (&#8220;less than 10 tickets left!&#8221;) then people are more likely to be forgiving.</p>
<p>In the world of online games, this translates to showing players the number of slots left in a game, but then handing the situation where there were 2 slots left but you were the third person to hit <img class="alignnone size-full wp-image-93" title="X marks the spot" src="http://nateware.files.wordpress.com/2010/07/playstation-button-x.png?w=12&#038;h=12" alt="X button" width="12" height="12" />.  You <strong>always</strong> need to handle these errors, because there&#8217;s no way to completely eliminate race conditions in a networked application.</p>
<h2>Recovering from Hiccups</h2>
<p><a href="http://nateware.files.wordpress.com/2010/07/isharescapsize.jpg"><img class="alignleft size-medium wp-image-83" title="Oopsie" src="http://nateware.files.wordpress.com/2010/07/isharescapsize.jpg?w=300&#038;h=232" alt="A boat upside-down" width="300" height="232" /></a>Sooner or later, your slick, smooth-running atomic system is going to have problems.  Even if it&#8217;s well-engineered,  you could have a large outage such as a system crash, datacenter failure, etc.  Plan on it.</p>
<p>Using Redis to offload atomic ops from the DB yielded big performance benefits, but added fragility.  You now have two systems that must stay in sync.  If either one crashes, there&#8217;s the possibility that you&#8217;re going to have dangling locks for records that are ok, or vice-versa.  So you need a way to clear them.  In a perfect world with infinite time, you&#8217;d be able to engineer a self-detecting, self-repairing system that can auto-recover.  Good luck with that.  A cron job that deletes locks older than a certain time works pretty well for the rest of us.</p>
<p>It&#8217;s also a good idea to have a script you can run manually, in the event you know you need to reset certain things.  For example, to handle the case where you know your Redis node went down, you could have a script that deletes all locks where the ID is &lt; the current max ID in the DB.  Oracle and other systems have similar concepts built into their <a title="How to release an Oracle lock" href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_lock.htm">native locking procedures</a>.</p>
<h2>Troubleshooting Redis is a Pain</h2>
<p>Unfortunately, Redis is lacking in the way of tools because it is still young.  There is the PHP <a title="Redis Admin" href="http://code.google.com/p/redis-admin/">Redis Admin</a> app, but its development appears to have stalled.  Beyond that it&#8217;s pretty much roll-your-own-scripts at this point.  (We&#8217;ve thought about developing a general-purpose Redis app/tool ourselves, but with the Redis 2.0 changes and <a title="Antirez gets a job" href="http://antirez.com/post/vmware-the-new-redis-home.html">VMWare hiring Salvatore</a>, the tools side is a bit &#8220;wait and see&#8221;.)</p>
<p>So before you start throwing all of your critical data into Redis, realize it&#8217;s a bit black-box at this point (or at least, a really dark gray).  I&#8217;m not a GUI guy personally &#8211; I prefer command-line tools due to my sysadmin days &#8211; but for many programmers, GUI tools help debugging <em>a lot</em>.  You need to make sure your programmers working with Redis can debug it when you have problems, which means a bigger investment in scripts vs. just downloading <a title="MySQL Workbench" href="http://wb.mysql.com/">MySQL Workbench</a> or <a title="Oracle SQL Developer" href="http://www.oracle.com/technology/products/database/sql_developer/index.html">Oracle SQL Developer</a>.</p>
<h2>Check and Double-Check</h2>
<p><a href="http://nateware.files.wordpress.com/2010/07/double-check.gif"><img class="alignright size-thumbnail wp-image-96" title="Double check" src="http://nateware.files.wordpress.com/2010/07/double-check.gif?w=150&#038;h=86" alt="" width="150" height="86" /></a>The last thing worth mentioning is this: Don&#8217;t trust your own app.  Even if you have an atomic gate at the start of a transaction, do sanity checking at the end too.  There are a few reasons for this:</p>
<ul>
<li>The lock may have expired for some reason, and you didn&#8217;t test for this</li>
<li>Your locking server may have crashed when you&#8217;re in the middle of a transaction</li>
<li>There could be a background job overlapping with a front-end transaction</li>
<li>Your software may have bugs (improbable, I know)</li>
</ul>
<p>For example, we had a background job that was using the same lock as a front-end service.  This ended up being a design mistake, but it was difficult to track down because it happened very infrequently.  The only way we found it was we had assertions that would get hit periodically on supposedly impossible conditions.  Once we correlated the times with the background job running, we were able to fix the issue rather quickly.</p>
<p>So my opinion is this: Try to do the right thing, but if it screws up, apologize to the user, recover, and move on.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nateware.wordpress.com/67/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nateware.wordpress.com/67/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nateware.wordpress.com/67/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nateware.wordpress.com/67/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nateware.wordpress.com/67/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nateware.wordpress.com/67/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nateware.wordpress.com/67/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nateware.wordpress.com/67/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nateware.wordpress.com/67/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nateware.wordpress.com/67/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nateware.wordpress.com/67/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nateware.wordpress.com/67/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nateware.wordpress.com/67/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nateware.wordpress.com/67/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nateware.com&amp;blog=12799998&amp;post=67&amp;subd=nateware&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nateware.com/2010/06/14/atomic-rant-redux/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/69f4b9b411dfcaebe01d0fde8c751726?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nwiger</media:title>
		</media:content>

		<media:content url="http://nateware.files.wordpress.com/2010/07/new-moon-official-cast.jpg?w=300" medium="image">
			<media:title type="html">The most amazing actors EVER</media:title>
		</media:content>

		<media:content url="http://nateware.files.wordpress.com/2010/07/beerbongs.jpg?w=91" medium="image">
			<media:title type="html">No I don&#039;t know these people - really</media:title>
		</media:content>

		<media:content url="http://nateware.files.wordpress.com/2010/07/playstation-button-x.png" medium="image">
			<media:title type="html">X marks the spot</media:title>
		</media:content>

		<media:content url="http://nateware.files.wordpress.com/2010/07/isharescapsize.jpg?w=300" medium="image">
			<media:title type="html">Oopsie</media:title>
		</media:content>

		<media:content url="http://nateware.files.wordpress.com/2010/07/double-check.gif?w=150" medium="image">
			<media:title type="html">Double check</media:title>
		</media:content>
	</item>
		<item>
		<title>An Atomic Rant</title>
		<link>http://nateware.com/2010/02/18/an-atomic-rant/</link>
		<comments>http://nateware.com/2010/02/18/an-atomic-rant/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 05:10:48 +0000</pubDate>
		<dc:creator>Nate Wiger</dc:creator>
				<category><![CDATA[Techie Bits]]></category>

		<guid isPermaLink="false">http://nateware.com/?p=35</guid>
		<description><![CDATA[Spoiler: If you&#8217;re part of the ADHD generation and want to skip learning and go straight to the punchline, use Redis and redis-objects for all your atomic data needs. Brush Up Your Resume You are probably not handling atomic operations properly in your app, and probably have some nasty lurking race conditions. The worst part [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nateware.com&amp;blog=12799998&amp;post=35&amp;subd=nateware&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Spoiler: If you&#8217;re part of the ADHD generation and want to skip learning and go straight to the punchline, use Redis and <a href="http://github.com/nateware/redis-objects">redis-objects</a> for all your atomic data needs.</p>
<h2>Brush Up Your Resume</h2>
<p>You are probably not handling atomic operations properly in your app, and probably have some nasty lurking race conditions. The worst part is these will get worse as your user count increases, are difficult to reproduce, and usually happen in your most critical pieces of code. (And no, your rspec tests can’t catch them either.)</p>
<p>Let’s assume you’re writing an app to enable students to enroll in courses. You need to ensure that no more than 30 students can sign up for a given course. In your enrollment code, you have something like this:</p>
<pre>    @course = Course.find(1)
    if @course.num_students &lt; 30
      @course.course_students.create!(:student_id =&gt; 101)
      @course.num_students += 1
      @course.save!
    else
      # course is full
    end</pre>
<p>You’re screwed. You now have 32 people in your 30 person class, and you have no idea what happened.</p>
<p>&#8220;Well no duh,&#8221; you’re saying, &#8220;even the <a href="http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html">ActiveRecord docs mention locking</a>, so I’ll just use that.&#8221;</p>
<pre>    @course = Course.find(1, :lock =&gt; true)
    if @course.num_students &lt; 30
      # ...</pre>
<p>Nice try, but now you’ve introduced other issues. Any other piece of code in your <em>entire app</em> that needs to update <em>anything</em> about the course &#8211; maybe the course name, or start date, or location &#8211; is now serialized. If you need high concurrency, you’re screwed (still).</p>
<p>You think, &#8220;ah-ha, the problem is having a separate counter!&#8221;</p>
<pre>    @course = Course.find(1)
    if @course.course_students.count &lt; 30
      @course.course_students.create!(:student_id =&gt; 101)
    else
      # course is full
    end</pre>
<p>Nope. Still screwed.</p>
<h2>The Root Down</h2>
<p>It’s worth understanding the root issue, and how to address it.</p>
<p>Race conditions arise from the difference in time between <strong>evaluating</strong> and <strong>altering</strong> a value. In our example, we fetched the record, then checked the value, then changed it. The more lines of code between those operations, and the higher your user count, the bigger the window of opportunity for other clients to get the data in an inconsistent state.</p>
<p>Sometimes race conditions don’t matter in practice, since often a user is only operating on their own data. This has a race condition, but is probably ok:</p>
<pre>    @user = User.find(params[:id])
    @post = Post.create(:user_id =&gt; @user.id, :title =&gt; "Whattup")
    @user.total_posts += 1  # update my post count</pre>
<p>But this <em>would</em> be problematic:</p>
<pre>    @blog = Blog.find(params[:id])
    @post = Post.create(:blog_id =&gt; @blog.id, :title =&gt; "Whattup")
    @blog.total_posts += 1  # update post count across all users</pre>
<p>As multiple users could be adding posts concurrently.</p>
<p>In a traditional RDBMS, you can increment counters atomically (<strong>but NOT return them</strong>) by firing off an update statement that self-references the column:</p>
<pre>    update users set total_posts = total_posts + 1 where id = 372</pre>
<p>You may have seen <a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M002278">ActiveRecord&#8217;s increment_counter class method</a>, which wraps this functionality. This solves <em>half</em> the problem of updating the counters atomically. But this has the serious the side effect that your object is no longer in sync with the DB, so you get other issues:</p>
<pre>    @blog = Blog.find(params[:id])
    Blog.increment_counter :total_posts, @blog.id
    if @blog.total_posts == 1000
      # the 1000th poster - award them a gold star!</pre>
<p>The DB says 1000, but your @blog object still says 999, and the right person doesn’t get their gold star. Sad faces all around.</p>
<h2>A Better Way</h2>
<p>Bottom line: Any operation that can alter a value <strong>must</strong> return that value in the <em>same operation</em> for it to be atomic. If you do a separate get then set, or set then get, you’re open to a race condition. There are very few systems that support an &#8220;increment and return&#8221; type operation, and Redis is one of them (Oracle sequences are another).</p>
<p>When you think of the specific things that you need to ensure, many of these will reduce to numeric operations:</p>
<ul>
<li>Ensuring there are no more than 30 students in a course</li>
<li>Getting more than 2 but less than 6 people in a game</li>
<li>Keeping a chat room to a max of 50 people</li>
<li>Correctly recording the total number of blog posts</li>
<li>Only allowing one piece of code to reorder a large dataset at a time</li>
</ul>
<p>All except the last one can be implemented with counters. The last one will need a carefully placed lock.</p>
<p>The best way I’ve found to balance atomicity and concurrency is, for each value, actually create two counters:</p>
<ul>
<li>A counter you base logic on (eg, <tt>slots_taken</tt>)</li>
<li>A counter users see (eg, <tt>current_students</tt>)</li>
</ul>
<p>The reason you want two counters is you’ll need to change the value of the logic counter <strong>first</strong>, <em>before</em> checking it, to address any race conditions. This means the value can get wonky momentarily (eg, there could be 32 <tt>slots_taken</tt> for a 30-person course). This doesn’t affect its function &#8211; indeed, it’s part of what makes it work &#8211; but does mean you don’t want to display it.</p>
<p>So, taking our <tt>Course</tt> example:</p>
<pre>    class Course &lt; ActiveRecord::Base
      include Redis::Objects

      counter :slots_taken
      counter :current_students
    end</pre>
<p>Then:</p>
<pre>    @course = Course.find(1)
    @course.slots_taken.increment do |val|
      if val &lt;= @course.max_students
        @course.course_students.create!(:student_id =&gt; 101)
        @course.current_students.increment
      end
    end</pre>
<p>Race-condition free. Why? Because we&#8217;re checking the <em>direct result</em> of the increment operation against a value.  The set and get operations are one and the same, which is the crucial piece.  If that code block returns false, the counter is rewound, and no animals were harmed in this atomic op.</p>
<p>Then, due to the <tt>current_students</tt> counter, your views get consistent information about the course, since it will only be incremented on success. There is still a race condition where <tt>current_students</tt> could be less than the real number of <tt>CourseStudent</tt> records, but since you’ll be displaying these values in a view (after that block completes) you shouldn’t see this manifest in real-world usage.</p>
<p>Now you can sleep soundly, without fear of getting fired at 3am via an angry phone call from your boss. (At least, not about this…)</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nateware.wordpress.com/35/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nateware.wordpress.com/35/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nateware.wordpress.com/35/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nateware.wordpress.com/35/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nateware.wordpress.com/35/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nateware.wordpress.com/35/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nateware.wordpress.com/35/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nateware.wordpress.com/35/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nateware.wordpress.com/35/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nateware.wordpress.com/35/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nateware.wordpress.com/35/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nateware.wordpress.com/35/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nateware.wordpress.com/35/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nateware.wordpress.com/35/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nateware.com&amp;blog=12799998&amp;post=35&amp;subd=nateware&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nateware.com/2010/02/18/an-atomic-rant/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/69f4b9b411dfcaebe01d0fde8c751726?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nwiger</media:title>
		</media:content>
	</item>
		<item>
		<title>Doppelganger spotted in London!</title>
		<link>http://nateware.com/2008/10/16/doppelganger-spotted-in-london/</link>
		<comments>http://nateware.com/2008/10/16/doppelganger-spotted-in-london/#comments</comments>
		<pubDate>Fri, 17 Oct 2008 01:50:57 +0000</pubDate>
		<dc:creator>Nate Wiger</dc:creator>
				<category><![CDATA[Amusement]]></category>

		<guid isPermaLink="false">http://nateware.com/?p=3</guid>
		<description><![CDATA[Many people go their whole lives without finding their doppelganger, but not me. By chance last weekend I picked up a New York Times and flipped to the Business section. There, staring back at me, was this! I&#8217;ve been so absent-minded lately, that I thought it may actually be me. Did I go to London [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nateware.com&amp;blog=12799998&amp;post=3&amp;subd=nateware&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Many people go their whole lives without finding their <a title="look it up!" href="http://www.answers.com/doppelganger">doppelganger</a>, but not me.  By chance last weekend I picked up a New York Times and flipped to the Business section. There, staring back at me, was this!</p>
<p style="text-align:center;"><a href="http://nateware.files.wordpress.com/2010/03/newspaper-nate1.jpg"><img class="size-medium wp-image-7 aligncenter" title="My doppelganger... we ARE related!" src="http://nateware.files.wordpress.com/2010/03/newspaper-nate1.jpg?w=573&#038;h=480&#038;h=480" alt="" width="573" height="480" /></a></p>
<p>I&#8217;ve been so absent-minded lately, that I thought it may actually <em>be</em> me. Did I go to London last week to protest? That would explain the hangover. If it wasn&#8217;t me, who was this socialist protester, this anti-Nate that had surfaced? I mean, I know I&#8217;m part British, but I didn&#8217;t realize it was <em>that</em> big a part.</p>
<p>Then I had this fantasy that I was, come nightfall, some type of socialist secret agent, something straight out of the Cold War, leading an underground movement to topple world governments. Then I realized: that would be an awesome idea for a TV show. I could get somebody handsome, maybe a bit dark &#8211; like <a title="ok maybe not THAT dark" href="http://crime.about.com/od/famousdiduno/ig/celebrity_mugshots/slaterchristian.htm">Christian Slater</a> &#8211; to play me. As usual, somebody <a title="Sponsored by Chevy?" href="http://www.nbc.com/My_Own_Worst_Enemy/">stole my idea</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nateware.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nateware.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nateware.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nateware.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nateware.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nateware.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nateware.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nateware.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nateware.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nateware.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nateware.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nateware.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nateware.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nateware.wordpress.com/3/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nateware.com&amp;blog=12799998&amp;post=3&amp;subd=nateware&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nateware.com/2008/10/16/doppelganger-spotted-in-london/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/69f4b9b411dfcaebe01d0fde8c751726?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nwiger</media:title>
		</media:content>

		<media:content url="http://nateware.files.wordpress.com/2010/03/newspaper-nate1.jpg?w=573&#38;h=480" medium="image">
			<media:title type="html">My doppelganger... we ARE related!</media:title>
		</media:content>
	</item>
	</channel>
</rss>
