<?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>Yan Pritzker &#187; background</title>
	<atom:link href="http://yanpritzker.com/category/background/feed/" rel="self" type="application/rss+xml" />
	<link>http://yanpritzker.com</link>
	<description>photographer, entrepreneur, software engineer, musician, skier</description>
	<lastBuildDate>Sat, 21 Jan 2012 01:18:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
	<atom:link rel="next" href="http://yanpritzker.com/category/background/feed/?page=2" />

		<item>
		<title>Long running Threads in Rails and metaprogramming fun</title>
		<link>http://yanpritzker.com/2008/06/11/long-running-threads-in-rails-and-metaprogramming-fun/</link>
		<comments>http://yanpritzker.com/2008/06/11/long-running-threads-in-rails-and-metaprogramming-fun/#comments</comments>
		<pubDate>Wed, 11 Jun 2008 03:07:41 +0000</pubDate>
		<dc:creator>yan</dc:creator>
				<category><![CDATA[background]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[thoughts]]></category>
		<category><![CDATA[threads]]></category>

		<guid isPermaLink="false">http://skwpspace.com/?p=166</guid>
		<description><![CDATA[Disclaimer: This post contains evil (but highly fun!) code. Proceed at your own peril&#8230; I was recently designing an application that needed to execute some long running requests against an external host. If you&#8217;ve ever tried doing something like this in Rails, you&#8217;ll find your mongrels will block up waiting for the request to complete, [...]]]></description>
			<content:encoded><![CDATA[<p>Disclaimer: This post contains evil (but highly fun!) code. Proceed at your own peril&#8230;</p>
<p>I was recently designing an application that needed to execute some long running requests against an external host. If you&#8217;ve ever tried doing something like this in Rails, you&#8217;ll find your mongrels will block up waiting for the request to complete, bringing the experience for all other users to a halt. </p>
<p>I wanted to dispatch my long running request, return to the user, and then poll for results using AJAX. There are many ways to do background tasks in Rails, most of which require running an out of process background server with which you will communicate over some sort of queue or memcached. There&#8217;s <a href="http://backgroundrb.rubyforge.org/">BackgroundRb</a>, <a href="http://agilewebdevelopment.com/plugins/bj">Bj</a>, <a href="http://playtype.net/past/2008/2/6/starling_and_asynchrous_tasks_in_ruby_on_rails/">workling</a>, and so on, but this seemed overkill for my problem.</p>
<p>After reading a <a href="http://bibwild.wordpress.com/2007/08/28/threading-in-rails/">post on using Ruby Threads</a>, I decided to be brave and try this approach. I implemented a simple action which would spawn a thread and proceed to return the result whether it was ready or not. This action is polled via AJAX and on the next poll the result will be correct. The pseudocode looks something like</p>
<pre class="textmate-source black_pearl"><span class="source source_ruby"><span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">long_running_action</span></span>
<span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">  <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span>spawn a thread
</span>  precache_the_results

<span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">  <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> This action throws DataNotAvailableException
</span><span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">  <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> if file is missing/unreadable
</span>  results <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> read_cached_results

<span class="keyword keyword_control keyword_control_ruby">rescue</span> <span class="variable variable_other variable_other_constant variable_other_constant_ruby">DataNotAvailableException</span>
<span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">  <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> This tells me that when I load the page
</span><span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">  <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> I should invoke an ajax a couple seconds
</span><span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">  <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> later to check for results again
</span>  flash<span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[</span><span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>update_right_away</span><span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">]</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="constant constant_language constant_language_ruby">true</span>
<span class="keyword keyword_control keyword_control_ruby">ensure</span>
  respond_to <span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby">do </span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span><span class="variable variable_other variable_other_block variable_other_block_ruby">wants</span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span>
<span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">    <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> render an RJS update with the results
</span>  <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="keyword keyword_control keyword_control_ruby">end</span>

<span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">precache_the_results</span></span>
  <span class="support support_class support_class_ruby">Thread</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">new</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">{</span><span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block">
</span>    expensive_action_outputs_to<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>file.txt<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
  <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">}</span>
<span class="keyword keyword_control keyword_control_ruby">end</span></span></pre>
<p>Because I didn&#8217;t <code>join</code> the Thread to the request thread, it lives on after the request completes, which is just what I needed. Since the code inside my Thread is a call to an external provider and doesn&#8217;t write to the database, I am not concerned with ActiveRecord threading issues.</p>
<p><b>The only problem</b> with this approach is that in development mode, Rails likes to reload your classes on every request. But if your thread runs past the request lifetime, the class that&#8217;s running it may be unloaded while it&#8217;s running, wreaking all sorts of havoc. But Ruby allows us the power to be <em>truly evil:</em>. What if I just prevent Threads from doing what they want to in development mode? Turns out I can!</p>
<pre class="textmate-source black_pearl"><span class="source source_ruby source_ruby_rails"><span class="keyword keyword_control keyword_control_ruby">if</span> <span class="meta meta_environment-variable meta_environment-variable_ruby"><span class="variable variable_other variable_other_constant variable_other_constant_ruby">ENV</span>[<span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>RAILS_ENV<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span>]</span> <span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby">==</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>development<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span>
<span class="meta meta_class meta_class_ruby">  <span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">Thread</span></span>
    <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">initialize</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"><span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">&amp;</span>block</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
      block<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>call
    <span class="keyword keyword_control keyword_control_ruby">end</span>
  <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="keyword keyword_control keyword_control_ruby">end</span>
</span></pre>
<p>This code is defined in the class where I&#8217;m doing the magic. Do NOT just slap this into your environment.rb as you&#8217;ll horribly break the Rails startup logic. There&#8217;s probably a slightly smarter and safer way to do this by using a Factory pattern to create the threads and explicitly specifying the implementation you want. But this is my party and I&#8217;ll monkeypatch if I want to.</p>
<p>So..comments, suggestions, complaints? Is this going to die horribly in production? I guess we&#8217;ll have to see!</p>
]]></content:encoded>
			<wfw:commentRss>http://yanpritzker.com/2008/06/11/long-running-threads-in-rails-and-metaprogramming-fun/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>

