After hearing lots of buzz surrounding Goliath the new asynchronous web server for ruby I thought I would give it a try for a particular problem I had. As part of COVE , an open source online video ethnography tool, we have to handle large video file uploads. The application is written in Rails which is great except when you have really long running connections. With long running connections it ties up your mongrels and reduces your ability to service request.
The reason for this is because Rails is an inherently I/O blocking.
When you run your application in production using
Passenger or Unicorn you essentially fork worker processes which are each responsible for servicing 1 requests at a time. To prevent memory bloating if a worker takes to long to respond or consumes too much memory it is killed. Well that presents a bit of a problem when you are talking about streaming file uploads that will require an active connection be left open while the file is uploaded. This large file upload request will block one of our worker processes which present an interesting problem. Since our process is blocked it is unable to service any additional request. This will lead to serious response time issues as our worker will be tied up handling these slow requests. To solve this we could spin up more worker processes, but this in turn takes more memory and more CPU and more resources in general.There must be a simpler solution!
It turns out there is in fact a simpler solution…Event Driven Programming and the
Reactor Pattern . I know what you are thinking, He’s talking about NodeJS. Well yes and no, NodeJS is indeed a javascript event based asyncronous web server. However, I like ruby and I want to program my web service in ruby so where does that leave me; Eventmachine . EventMachine is a c++ based event-processing library with a rich ruby API that allows for event oriented programming using an event loop and callbacks. Programming a web service using EventMachine can be a little bit of a pain in the ass as your code quickly starts to look like spaghetti and that is where Goliath comes in.
Goliath is described as “Non-blocking, Ruby 1.9 Web Server.” It supports
the full rack API and utilizes ruby 1.9.2’s fibers to make readable top
down code. If you want to learn more you can check out some great
articles by Ilya Grigorik . Essentially goliath gives us a great way to write code that follows a top down flow and it easy to read, but in reality it is running asynchronously using EventMachine. Now what the heck does that mean to me you ask. Well what that means is in under 30 lines of code I was able to write an asynchronous file upload server.
And here it is:
<!DOCTYPE html>
<html>
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# githubog: http://ogp.me/ns/fb/githubog#">
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Server Error · GitHub</title>
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub" />
<link rel="fluid-icon" href="http://github.com/fluidicon.png" title="GitHub" />
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="apple-touch-icon-114.png" />
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="apple-touch-icon-114.png" />
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="apple-touch-icon-144.png" />
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="apple-touch-icon-144.png" />
<link rel="icon" type="image/x-icon" href="/favicon.png" />
<meta content="authenticity_token" name="csrf-param" />
<meta content="VbKnrox0gfmVve2V14mMMnkwttWgMHzJhow6TYD+dIg=" name="csrf-token" />
<link href="https://a248.e.akamai.net/assets.github.com/assets/github-a49d58ce18e6b9d05e6a5dfec4630525766e1ece.css" media="screen" rel="stylesheet" type="text/css" />
<link href="https://a248.e.akamai.net/assets.github.com/assets/github2-c8326b04f9d01e175322b58e4789bc4520b7016a.css" media="screen" rel="stylesheet" type="text/css" />
<script src="https://a248.e.akamai.net/assets.github.com/assets/frameworks-0f165a24ede5fce08cc34dbaba10d16d4ce5e4ac.js" type="text/javascript"></script>
<script defer="defer" src="https://a248.e.akamai.net/assets.github.com/assets/github-b7618679cbb78275710b9e29160ab1c26a3d09a8.js" type="text/javascript"></script>
</head>
<body class="logged_out env-production ">
<div id="wrapper">
<div id="header" class="true clearfix">
<div class="container clearfix">
<a class="site-logo " href="http://github.com/">
<img alt="GitHub" class="github-logo-4x" height="30" src="https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7@4x.png?1340659530" />
<img alt="GitHub" class="github-logo-4x-hover" height="30" src="https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7@4x-hover.png?1340659530" />
</a>
<!--
make sure to use fully qualified URLs here since this nav
is used on error pages on other domains
-->
<ul class="top-nav logged_out">
<li class="pricing"><a href="https://github.com/plans">Signup and Pricing</a></li>
<li class="explore"><a href="https://github.com/explore">Explore GitHub</a></li>
<li class="features"><a href="https://github.com/features">Features</a></li>
<li class="blog"><a href="https://github.com/blog">Blog</a></li>
<li class="login"><a href="https://github.com/login">Sign in</a></li>
</ul>
</div>
</div>
<div class="site clearfix">
<div id="site-container" class="container" data-pjax-container>
<div class="markdown-body standard">
<div class="center" id="error_502"><img alt="Unicorn is angry" height="205" src="https://a248.e.akamai.net/assets.github.com/images/error/angry_unicorn.png?1340659530" width="200" /></div>
<h1>Page did not respond in a timely fashion.</h1>
<p><a href="http://status.github.com">Check our status site for alerts.</a></p>
<p>
Either you found a page that took too long to render or<br />
we're getting more requests right now than we can handle.
</p>
<ul>
<li>
You can try
<a href="javascript: window.location.reload()">refreshing the page,</a>
the problem may be temporary.
</li>
<li>
<a href="http://github.s3.amazonaws.com/misc/down.html">
Learn how to deal with GitHub outages and other access problems.
</a>
</li>
</ul>
</div>
</div>
<div class="context-overlay"></div>
</div>
<div id="footer-push"></div><!-- hack for sticky footer -->
</div><!-- end of wrapper - hack for sticky footer -->
<!-- footer -->
<div id="footer" >
<div class="upper_footer">
<div class="container clearfix">
<!--[if IE]><h4 id="blacktocat_ie">GitHub Links</h4><![endif]-->
<![if !IE]><h4 id="blacktocat">GitHub Links</h4><![endif]>
<ul class="footer_nav">
<h4>GitHub</h4>
<li><a href="https://github.com/about">About</a></li>
<li><a href="https://github.com/blog">Blog</a></li>
<li><a href="https://github.com/features">Features</a></li>
<li><a href="https://github.com/contact">Contact & Support</a></li>
<li><a href="https://github.com/training">Training</a></li>
<li><a href="http://enterprise.github.com/">GitHub Enterprise</a></li>
<li><a href="http://status.github.com/">Site Status</a></li>
</ul>
<ul class="footer_nav">
<h4>Clients</h4>
<li><a href="http://mac.github.com/">GitHub for Mac</a></li>
<li><a href="http://windows.github.com/">GitHub for Windows</a></li>
<li><a href="http://eclipse.github.com/">GitHub for Eclipse</a></li>
<li><a href="http://mobile.github.com/">GitHub Mobile Apps</a></li>
</ul>
<ul class="footer_nav">
<h4>Tools</h4>
<li><a href="http://get.gaug.es/">Gauges: Web analytics</a></li>
<li><a href="http://speakerdeck.com">Speaker Deck: Presentations</a></li>
<li><a href="https://gist.github.com">Gist: Code snippets</a></li>
<h4 class="second">Extras</h4>
<li><a href="http://jobs.github.com/">Job Board</a></li>
<li><a href="http://shop.github.com/">GitHub Shop</a></li>
<li><a href="http://octodex.github.com/">The Octodex</a></li>
</ul>
<ul class="footer_nav">
<h4>Documentation</h4>
<li><a href="http://help.github.com/">GitHub Help</a></li>
<li><a href="http://developer.github.com/">Developer API</a></li>
<li><a href="http://github.github.com/github-flavored-markdown/">GitHub Flavored Markdown</a></li>
<li><a href="http://pages.github.com/">GitHub Pages</a></li>
</ul>
</div><!-- /.site -->
</div><!-- /.upper_footer -->
<div class="lower_footer">
<div class="container clearfix">
<!--[if IE]><div id="legal_ie"><![endif]-->
<![if !IE]><div id="legal"><![endif]>
<ul>
<li><a href="https://github.com/site/terms">Terms of Service</a></li>
<li><a href="https://github.com/site/privacy">Privacy</a></li>
<li><a href="https://github.com/security">Security</a></li>
</ul>
<p>© 2012 <span title="s from fe17.rs.github.com">GitHub</span> Inc. All rights reserved.</p>
</div><!-- /#legal or /#legal_ie-->
</div><!-- /.site -->
</div><!-- /.lower_footer -->
</div><!-- /#footer -->
<div id="keyboard_shortcuts_pane" class="instapaper_ignore readability-extra" style="display:none">
<h2>Keyboard Shortcuts <small><a href="#" class="js-see-all-keyboard-shortcuts">(see all)</a></small></h2>
<div class="columns threecols">
<div class="column first">
<h3>Site wide shortcuts</h3>
<dl class="keyboard-mappings">
<dt>s</dt>
<dd>Focus site search</dd>
</dl>
<dl class="keyboard-mappings">
<dt>?</dt>
<dd>Bring up this help dialog</dd>
</dl>
</div><!-- /.column.first -->
<div class="column middle" style='display:none'>
<h3>Commit list</h3>
<dl class="keyboard-mappings">
<dt>j</dt>
<dd>Move selection down</dd>
</dl>
<dl class="keyboard-mappings">
<dt>k</dt>
<dd>Move selection up</dd>
</dl>
<dl class="keyboard-mappings">
<dt>c <em>or</em> o <em>or</em> enter</dt>
<dd>Open commit</dd>
</dl>
<dl class="keyboard-mappings">
<dt>y</dt>
<dd>Expand URL to its canonical form</dd>
</dl>
</div><!-- /.column.first -->
<div class="column last js-hidden-pane" style='display:none'>
<h3>Pull request list</h3>
<dl class="keyboard-mappings">
<dt>j</dt>
<dd>Move selection down</dd>
</dl>
<dl class="keyboard-mappings">
<dt>k</dt>
<dd>Move selection up</dd>
</dl>
<dl class="keyboard-mappings">
<dt>o <em>or</em> enter</dt>
<dd>Open issue</dd>
</dl>
<dl class="keyboard-mappings">
<dt><span class="platform-mac">⌘</span><span class="platform-other">ctrl</span> <em>+</em> enter</dt>
<dd>Submit comment</dd>
</dl>
<dl class="keyboard-mappings">
<dt><span class="platform-mac">⌘</span><span class="platform-other">ctrl</span> <em>+</em> shift p</dt>
<dd>Preview comment</dd>
</dl>
</div><!-- /.columns.last -->
</div><!-- /.columns.equacols -->
<div class="js-hidden-pane" style='display:none'>
<div class="rule"></div>
<h3>Issues</h3>
<div class="columns threecols">
<div class="column first">
<dl class="keyboard-mappings">
<dt>j</dt>
<dd>Move selection down</dd>
</dl>
<dl class="keyboard-mappings">
<dt>k</dt>
<dd>Move selection up</dd>
</dl>
<dl class="keyboard-mappings">
<dt>x</dt>
<dd>Toggle selection</dd>
</dl>
<dl class="keyboard-mappings">
<dt>o <em>or</em> enter</dt>
<dd>Open issue</dd>
</dl>
<dl class="keyboard-mappings">
<dt><span class="platform-mac">⌘</span><span class="platform-other">ctrl</span> <em>+</em> enter</dt>
<dd>Submit comment</dd>
</dl>
<dl class="keyboard-mappings">
<dt><span class="platform-mac">⌘</span><span class="platform-other">ctrl</span> <em>+</em> shift p</dt>
<dd>Preview comment</dd>
</dl>
</div><!-- /.column.first -->
<div class="column last">
<dl class="keyboard-mappings">
<dt>c</dt>
<dd>Create issue</dd>
</dl>
<dl class="keyboard-mappings">
<dt>l</dt>
<dd>Create label</dd>
</dl>
<dl class="keyboard-mappings">
<dt>i</dt>
<dd>Back to inbox</dd>
</dl>
<dl class="keyboard-mappings">
<dt>u</dt>
<dd>Back to issues</dd>
</dl>
<dl class="keyboard-mappings">
<dt>/</dt>
<dd>Focus issues search</dd>
</dl>
</div>
</div>
</div>
<div class="js-hidden-pane" style='display:none'>
<div class="rule"></div>
<h3>Issues Dashboard</h3>
<div class="columns threecols">
<div class="column first">
<dl class="keyboard-mappings">
<dt>j</dt>
<dd>Move selection down</dd>
</dl>
<dl class="keyboard-mappings">
<dt>k</dt>
<dd>Move selection up</dd>
</dl>
<dl class="keyboard-mappings">
<dt>o <em>or</em> enter</dt>
<dd>Open issue</dd>
</dl>
</div><!-- /.column.first -->
</div>
</div>
<div class="js-hidden-pane" style='display:none'>
<div class="rule"></div>
<h3>Network Graph</h3>
<div class="columns equacols">
<div class="column first">
<dl class="keyboard-mappings">
<dt><span class="badmono">←</span> <em>or</em> h</dt>
<dd>Scroll left</dd>
</dl>
<dl class="keyboard-mappings">
<dt><span class="badmono">→</span> <em>or</em> l</dt>
<dd>Scroll right</dd>
</dl>
<dl class="keyboard-mappings">
<dt><span class="badmono">↑</span> <em>or</em> k</dt>
<dd>Scroll up</dd>
</dl>
<dl class="keyboard-mappings">
<dt><span class="badmono">↓</span> <em>or</em> j</dt>
<dd>Scroll down</dd>
</dl>
<dl class="keyboard-mappings">
<dt>t</dt>
<dd>Toggle visibility of head labels</dd>
</dl>
</div><!-- /.column.first -->
<div class="column last">
<dl class="keyboard-mappings">
<dt>shift <span class="badmono">←</span> <em>or</em> shift h</dt>
<dd>Scroll all the way left</dd>
</dl>
<dl class="keyboard-mappings">
<dt>shift <span class="badmono">→</span> <em>or</em> shift l</dt>
<dd>Scroll all the way right</dd>
</dl>
<dl class="keyboard-mappings">
<dt>shift <span class="badmono">↑</span> <em>or</em> shift k</dt>
<dd>Scroll all the way up</dd>
</dl>
<dl class="keyboard-mappings">
<dt>shift <span class="badmono">↓</span> <em>or</em> shift j</dt>
<dd>Scroll all the way down</dd>
</dl>
</div><!-- /.column.last -->
</div>
</div>
<div class="js-hidden-pane" style='display:none'>
<div class="rule"></div>
<div class="columns threecols">
<div class="column first js-hidden-pane" style='display:none'>
<h3>Source Code Browsing</h3>
<dl class="keyboard-mappings">
<dt>t</dt>
<dd>Activates the file finder</dd>
</dl>
<dl class="keyboard-mappings">
<dt>l</dt>
<dd>Jump to line</dd>
</dl>
<dl class="keyboard-mappings">
<dt>w</dt>
<dd>Switch branch/tag</dd>
</dl>
<dl class="keyboard-mappings">
<dt>y</dt>
<dd>Expand URL to its canonical form</dd>
</dl>
</div>
</div>
</div>
<div class="js-hidden-pane" style='display:none'>
<div class="rule"></div>
<div class="columns threecols">
<div class="column first">
<h3>Browsing Commits</h3>
<dl class="keyboard-mappings">
<dt><span class="platform-mac">⌘</span><span class="platform-other">ctrl</span> <em>+</em> enter</dt>
<dd>Submit comment</dd>
</dl>
<dl class="keyboard-mappings">
<dt>escape</dt>
<dd>Close form</dd>
</dl>
<dl class="keyboard-mappings">
<dt>p</dt>
<dd>Parent commit</dd>
</dl>
<dl class="keyboard-mappings">
<dt>o</dt>
<dd>Other parent commit</dd>
</dl>
</div>
</div>
</div>
<div class="js-hidden-pane" style='display:none'>
<div class="rule"></div>
<h3>Notifications</h3>
<div class="columns threecols">
<div class="column first">
<dl class="keyboard-mappings">
<dt>j</dt>
<dd>Move selection down</dd>
</dl>
<dl class="keyboard-mappings">
<dt>k</dt>
<dd>Move selection up</dd>
</dl>
<dl class="keyboard-mappings">
<dt>o <em>or</em> enter</dt>
<dd>Open notification</dd>
</dl>
</div><!-- /.column.first -->
<div class="column second">
<dl class="keyboard-mappings">
<dt>e <em>or</em> shift i <em>or</em> y</dt>
<dd>Mark as read</dd>
</dl>
<dl class="keyboard-mappings">
<dt>shift m</dt>
<dd>Mute thread</dd>
</dl>
</div><!-- /.column.first -->
</div>
</div>
</div>
<div id="markdown-help" class="instapaper_ignore readability-extra">
<h2>Markdown Cheat Sheet</h2>
<div class="cheatsheet-content">
<div class="mod">
<div class="col">
<h3>Format Text</h3>
<p>Headers</p>
<pre>
# This is an <h1> tag
## This is an <h2> tag
###### This is an <h6> tag</pre>
<p>Text styles</p>
<pre>
*This text will be italic*
_This will also be italic_
**This text will be bold**
__This will also be bold__
*You **can** combine them*
</pre>
</div>
<div class="col">
<h3>Lists</h3>
<p>Unordered</p>
<pre>
* Item 1
* Item 2
* Item 2a
* Item 2b</pre>
<p>Ordered</p>
<pre>
1. Item 1
2. Item 2
3. Item 3
* Item 3a
* Item 3b</pre>
</div>
<div class="col">
<h3>Miscellaneous</h3>
<p>Images</p>
<pre>
![GitHub Logo](/images/logo.png)
Format: ![Alt Text](url)
</pre>
<p>Links</p>
<pre>
http://github.com - automatic!
[GitHub](http://github.com)</pre>
<p>Blockquotes</p>
<pre>
As Kanye West said:
> We're living the future so
> the present is our past.
</pre>
</div>
</div>
<div class="rule"></div>
<h3>Code Examples in Markdown</h3>
<div class="col">
<p>Syntax highlighting with <a href="http://github.github.com/github-flavored-markdown/" title="GitHub Flavored Markdown" target="_blank">GFM</a></p>
<pre>
```javascript
function fancyAlert(arg) {
if(arg) {
$.facebox({div:'#foo'})
}
}
```</pre>
</div>
<div class="col">
<p>Or, indent your code 4 spaces</p>
<pre>
Here is a Python code example
without syntax highlighting:
def foo:
if not bar:
return true</pre>
</div>
<div class="col">
<p>Inline code for comments</p>
<pre>
I think you should use an
`<addr>` element here instead.</pre>
</div>
</div>
</div>
</div>
<div id="ajax-error-message" class="flash flash-error">
<span class="mini-icon mini-icon-exclamation"></span>
Something went wrong with that request. Please try again.
<a href="#" class="mini-icon mini-icon-remove-close ajax-error-dismiss"></a>
</div>
<div id="logo-popup">
<h2>Looking for the GitHub logo?</h2>
<ul>
<li>
<h4>GitHub Logo</h4>
<a href="http://github-media-downloads.s3.amazonaws.com/GitHub_Logos.zip"><img alt="Github_logo" src="https://a248.e.akamai.net/assets.github.com/images/modules/about_page/github_logo.png?1340659530" /></a>
<a href="http://github-media-downloads.s3.amazonaws.com/GitHub_Logos.zip" class="minibutton download">Download</a>
</li>
<li>
<h4>The Octocat</h4>
<a href="http://github-media-downloads.s3.amazonaws.com/Octocats.zip"><img alt="Octocat" src="https://a248.e.akamai.net/assets.github.com/images/modules/about_page/octocat.png?1340659530" /></a>
<a href="http://github-media-downloads.s3.amazonaws.com/Octocats.zip" class="minibutton download">Download</a>
</li>
</ul>
</div>
</body>
</html>
This was just my first plunge into the world of Non-blocking evented code so I am by no means an expert. If you see that I have made a terrible mistake or just want to give me some pointers feel free to do some.
Just remember I am still young and while my college peers were out partying I was writing this code so try and make all criticism constructive
In my next post I will document the upload client that also takes
advantaged of EventMachine and fibers to compute checksums and upload
files to the web service.