<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>techno weenie</title>
  <id>tag:techno-weenie.net,2010:mephisto/</id>
  <generator uri="http://github.com/mojombo/jekyll" version="0.6.2">Jekyll</generator>
  <link href="http://techno-weenie.net/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://techno-weenie.net/" rel="alternate" type="text/html"/>
  <updated>2012-03-29T15:56:32-07:00</updated>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2012:3:19:ending-the-mass-assignment-party</id>
    <published>2012-03-19T00:00:00-07:00</published>
    <updated>2012-03-19T00:00:00-07:00</updated>
    <link href="/2012/3/19/ending-the-mass-assignment-party" rel="alternate" type="text/html"/>
    <title>Ending the Mass Assignment Party</title>
<content type="html">
&lt;p&gt;At GitHub, we've been going over various policies and patterns we use to ship
features.  One of the specific things is how we deal with mass assignment
issues.  There are 3 main ways we've handled it in the past:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;ActiveRecord::Base.attr_accessible&lt;/code&gt; to whitelist the attributes we can
set.  This is a great safety net, but leaves the controller looking unsafe:&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Slice the parameters hash in the controller.  You can do
&lt;a href=&quot;https://gist.github.com/1975644&quot;&gt;something simple&lt;/a&gt; or
&lt;a href=&quot;https://gist.github.com/1974187&quot;&gt;build some protection into Rails controllers&lt;/a&gt;.
This has the advantage of looking safer in the controller, isn't DRY.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post_hash&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;post_hash&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slice&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;You can wrap access to your data model around another abstraction layer.
You can go with something &lt;a href=&quot;https://gist.github.com/1978312&quot;&gt;completely custom&lt;/a&gt;,
or use something like &lt;a href=&quot;https://docs.djangoproject.com/en/dev/ref/forms/api/&quot;&gt;Django Forms&lt;/a&gt;
as another approach.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Having a common pattern is a great idea, as well as other organizational
patterns in use (testing, code review, etc).  But, we felt like we needed
something that would &lt;em&gt;force&lt;/em&gt; compliance with safe handling of user input in web
controllers.  Something that works with what we're already doing, but can't be
thwarted by someone writing lazy code.  Keep in mind, this person may be
someone from the past, that already shipped the code long before common
patterns were in place.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/technoweenie/tainted_hash&quot;&gt;TaintedHash&lt;/a&gt; is what we came
up with. It's a simple proxy to a protected inner Hash, that only exposes keys
that are requested by name.  If you're going to be passing the hash into
anything that iterates through its values, you'll have to tell it which keys to
expose:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# You can set properties manually:&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# You can still slice&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slice&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# You can&amp;#39;t do this anymore:&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# ... unless you tell it to expose some keys&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;It's a tiny class with no dependencies that hooks into Rails 2.3 with a simple
before filter:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;wrap_params_with_tainted_hash&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@_params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;TaintedHash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@_params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;It's meant to be very low level and simple.  It does work well with existing
ActiveRecord accessible attributes:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attr_accessible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;One other TaintedHash goal is that broken rules need to be easily called
out by &lt;code&gt;ack&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# #original_hash and #expose_all are probably easy to find through `ack`&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;original_hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;post&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expose_all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Currently the only place we use &lt;code&gt;#original_hash&lt;/code&gt; at all is to give the relevant
params to the Rails url writer.  If the right keys aren't exposed, Rails can't
build our URLs since there are no exposed values to iterate through.&lt;/p&gt;

&lt;p&gt;This has been active on GitHub for over a week.  If it works out, we'll probably
look at introducing it or something like it to our other various ruby apps that
are running in production. The branch did expose areas that weren't tested well
enough.  To help in the conversion of the entire app, I added code to raise
test exceptions in after filters if Hashes had any keys left over.  In production,
we simply logged any unexposed keys that were missed.&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2011:8:19:ie9-deletes-stuff</id>
    <published>2011-08-19T00:00:00-07:00</published>
    <updated>2011-08-19T00:00:00-07:00</updated>
    <link href="/2011/8/19/ie9-deletes-stuff" rel="alternate" type="text/html"/>
    <title>IE9 DELETES stuff</title>
<content type="html">
&lt;p&gt;So, &lt;a href=&quot;http://twitter.com/kneath&quot;&gt;Kyle&lt;/a&gt; and I discovered some interesting
IE9 behavior.  Redirect responses from DELETE requests are followed with
another DELETE.  How is this surprising?&lt;/p&gt;

&lt;center&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Planetary_(comics)&quot;&gt;
&lt;img src=&quot;/images/2011/timetravel.jpg&quot; /&gt;
&lt;/a&gt;
&lt;/center&gt;


&lt;p&gt;Using more of the HTTP methods lets us keep the URLs cleaner.  Web
browsers don't understand PUT/PATCH/DELETE in forms, so a workaround was needed.  Rails looks at a
&lt;code&gt;_method&lt;/code&gt; GET parameter on POST requests to determine what HTTP verb it should
be recognized as.  The &lt;a href=&quot;http://code.google.com/apis/gdata/docs/2.0/basics.html#UpdatingEntry&quot;&gt;GData API&lt;/a&gt;
supports this behavior through the &lt;code&gt;X-HTTP-Method-Override&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;A typical Rails controller might look like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WidgetsController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# DELETE /widgets/1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;destroy&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@widget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroy&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/widgets&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;If you don't like Rails, just close your eyes and think of your favorite
web framework...&lt;/p&gt;

&lt;p&gt;This action works great for a simple form in a browser.  You click
&quot;Submit&quot;,
it POSTs to the server, and then you end up back at the root page.
Then, you can add some jQuery to spice things up for newer browsers.
Progressive enhancement and all that.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;.remove-widget&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;del&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// celebrate, disable a spinner, etc&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This works great in all modern browsers, except IE9.  We discovered that not
only does IE9 send a real DELETE request, it also &lt;em&gt;follows the redirect&lt;/em&gt;
with another DELETE.  If that redirect points to another resource, you
can get a dangerous cascading effect.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-10.3.3&quot;&gt;RFC 2616&lt;/a&gt; is not clear about what to do in this case, but strongly
suggests that redirects are not automatically followed unless coming
from a &lt;a href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html&quot;&gt;safe method&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;If the 302 status code is received in response to a request other than GET
or HEAD, the user agent MUST NOT automatically redirect the request unless
it can be confirmed by the user, since this might change the conditions under
which the request was issued.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Standard practice for browsers over the years is that redirects from
POST requests are followed with a GET request.  GET/HEAD requests are
&lt;a href=&quot;http://37signals.com/svn/archives2/google_web_accelerator_hey_not_so_fast_an_alert_for_web_app_designers.php&quot;&gt;usually safe&lt;/a&gt;, so this seems like reasonable
behavior.  It's expected by web developers, and consistent across
browsers.&lt;/p&gt;

&lt;p&gt;I can't imagine that this behavior in IE9 was on purpose.  It feels like
an edge case that slipped through an if statement because &lt;code&gt;&quot;DELETE&quot; !=
&quot;POST&quot;&lt;/code&gt;.  I've submitted feedback to the IE9 team about this issue.  I'm curious
to see what they say.&lt;/p&gt;

&lt;p&gt;So, if your application might be responding to ajax requests with
redirects, you should probably start sending back &lt;code&gt;200 OK&lt;/code&gt;...&lt;/p&gt;

&lt;center&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Planetary_(comics)&quot;&gt;
&lt;img src=&quot;/images/2011/strangeworld.jpg&quot; /&gt;
&lt;/a&gt;
&lt;/center&gt;


&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Eric Law on the &lt;a href=&quot;http://blogs.msdn.com/b/ieinternals/archive/2011/08/19/understanding-the-impact-of-redirect-response-status-codes-on-http-methods-like-head-get-post-and-delete.aspx&quot;&gt;IEInternals blog&lt;/a&gt; responded to one of Kyle's
tweets.  Apparently the behavior is correct according to HTTP 1.0, and
IE has been following DELETE redirects since at least IE6.&lt;/p&gt;

&lt;p&gt;Here's the breakdown of browser behavior when receiving a 302 redirect from
a DELETE request:&lt;/p&gt;

&lt;table class=&quot;humblebrag&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot;&gt;IE 6-10&lt;/td&gt;
&lt;td valign=&quot;top&quot;&gt;DELETE method is preserved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot;&gt;Chrome 13&lt;/td&gt;
&lt;td valign=&quot;top&quot;&gt;Converts to GET&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot;&gt;Firefox 6&lt;/td&gt;
&lt;td valign=&quot;top&quot;&gt;Converts to GET&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot;&gt;Safari 5.1&lt;/td&gt;
&lt;td valign=&quot;top&quot;&gt;Converts to GET&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot;&gt;Opera 11.5&lt;/td&gt;
&lt;td valign=&quot;top&quot;&gt;Converts to GET&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;


&lt;p&gt;We didn't see the behavior in IE8, so we assumed it was new to IE9. At least,
no one was sending in crazy bug reports from other browsers. This is another
example why developers hate dealing with IE.  Kudos to the standards
compliance, though!&lt;/p&gt;

&lt;p&gt;Discuss this post on &lt;a href=&quot;http://news.ycombinator.com/item?id=2903493&quot;&gt;Hacker News&lt;/a&gt;.&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2011:7:16:npm-rocks</id>
    <published>2011-07-16T00:00:00-07:00</published>
    <updated>2011-07-16T00:00:00-07:00</updated>
    <link href="/2011/7/16/npm-rocks" rel="alternate" type="text/html"/>
    <title>NPM rocks</title>
<content type="html">
&lt;p&gt;It is very easy to write and distribute packaged ruby libraries to the
world.  You slap a gemspec file on it, push it to rubygems.org, and
anyone can get it.  Tools like &lt;a href=&quot;https://rubygems.org/gems/jeweler&quot;&gt;Jeweler&lt;/a&gt;
(though I roll with &lt;a href=&quot;https://github.com/mojombo/rakegem&quot;&gt;rakegem&lt;/a&gt; these days)
and &lt;a href=&quot;https://github.com/rubygems/gemcutter&quot;&gt;gemcutter&lt;/a&gt; made it
ridiculously easy to push ruby gems.&lt;/p&gt;

&lt;p&gt;But, ruby gems are far from perfect (and no, I'm talking about the drama
around slimgems).  Unfortunately, a lot of problems emerged over time
for various reasons, and will be tough to solve.&lt;/p&gt;

&lt;p&gt;Node.js is an extremely young programming community that I've been
following for well over a year now.  It's been interesting to see the
node packaging landscape grow this time, in contrast to my own early
experiences with ruby gems.  In this time, &lt;a href=&quot;https://github.com/isaacs/npm&quot;&gt;npm&lt;/a&gt; has
emerged as the dominant node packaging system.  Npm is written by Isaac
Schlueter, based on his experience using Yinst at Yahoo.&lt;/p&gt;

&lt;p&gt;The first, and biggest reason that I love npm is that it's not loaded at
runtime.  You never need to &lt;code&gt;require('npm')&lt;/code&gt; for your library to
function.  This is in stark contrast to ruby libraries, where &lt;a href=&quot;http://tomayko.com/writings/require-rubygems-antipattern&quot;&gt;nearly
every one of them requires rubygems&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Why is that?  Say you're writing a sweet web service, and you want to
require a database adapter:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;mysql&amp;#39;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SweetApp&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Boom: &lt;code&gt;LoadError&lt;/code&gt;.  Where is the mysql library?  Oh, let's just use
rubygems:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;mysql&amp;#39;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SweetApp&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now, check out your load path.  Depending on system, it should have an
entry like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/Library/Ruby/Gems/1.8/gems/mysql-1.0.0/lib
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Just to get mysql loaded, we had to load rubygems, and have it find the
correct lib path for us.  It does this every time your app boots up.
After a while, your app likely has 30-100 (or 208, in the case of
GitHub) gems loaded, each with its own entry in the load path.  Every
time you require something, ruby has to scan the whole list until it
finds a match.  God help you if you try to require something with a
common name.&lt;/p&gt;

&lt;p&gt;Why doesn't this happen with node?  &lt;code&gt;index.js&lt;/code&gt;.  Let's look at a node
port of my sweet web service:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;mysql&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;mysql&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;SweetApp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Assuming you installed the mysql lib with npm, node will check for these
files:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;./node_modules/mysql.js
./node_modules/mysql/index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It can also look in node's load path (though it sounds like this may be
removed in the future).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; require.paths
[ '/Users/technoweenie/.node_modules'
, '/Users/technoweenie/.node_libraries'
, '/usr/local/lib/node'
]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Loading packages from npm (or wherever) doesn't add to the load path.
NPM just knows how to install packages so that node can easily find
them.&lt;/p&gt;

&lt;p&gt;Without some kind of &lt;code&gt;index.rb&lt;/code&gt; file, ruby forces all ruby libraries to
live in separate directories, usually with its own load path entry.  Or,
you can combine the files together like the ruby standard lib:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ls /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8
English.rb           debug.rb             forwardable.rb       logger.rb
Env.rb               delegate.rb          ftools.rb            mailread.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Newer versions of node have even started cooperating with npm through
the &lt;code&gt;package.json&lt;/code&gt; file.  Your package can provide a &lt;code&gt;package.json&lt;/code&gt; file
instead of &lt;code&gt;index.js&lt;/code&gt;, and node will find it.  The following file is
from the mysql package, and instructs node to find the local &lt;code&gt;lib/mysql.js&lt;/code&gt; when
you &lt;code&gt;require('mysql')&lt;/code&gt; from your app.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cat node_modules/mysql/package.json 
{ &quot;name&quot; : &quot;mysql&quot;
, &quot;version&quot;: &quot;0.9.1&quot;
, &quot;main&quot; : &quot;./lib/mysql&quot;
...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Newer versions of node and npm also support the idea of cascading
&lt;code&gt;node_modules&lt;/code&gt; directories.  If you have an app at &lt;code&gt;/home/rick/app&lt;/code&gt;,
node will check these directories for libraries:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/home/rick/app/node_modules
/home/rick/node_modules
/home/node_modules
/node_modules
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This makes it easy to bundle libraries with your node apps.  You can
commit them directly and know they'll run wherever you push them (though
this may not work for npm packages that require compilation).  You can
also setup a &lt;code&gt;package.json&lt;/code&gt; file like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
  &quot;name&quot; : &quot;alambic&quot;
, &quot;version&quot; : &quot;0.0.1&quot;
, &quot;dependencies&quot; :
  { &quot;mysql&quot; : &quot;0.9&quot;
  , &quot;coffee-script&quot; : &quot;1.0&quot;
  , &quot;formidable&quot;: &quot;1.0.2&quot;
  , &quot;underscore&quot;: &quot;1.1.7&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running &lt;code&gt;npm install&lt;/code&gt; will load these to the &lt;code&gt;node_modules&lt;/code&gt; directory
inside my app.  I can run this once after updating code on our servers,
and it's ready to rock.  This feature is reminiscent of Bundler, but
again, it doesn't rely on your app using npm at runtime.&lt;/p&gt;

&lt;p&gt;You can comment on this through the &lt;a href=&quot;http://news.ycombinator.com/item?id=2818299&quot;&gt;HN discussion&lt;/a&gt;...&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2011:6:19:reliable-zeromq-pub-sub</id>
    <published>2011-06-19T00:00:00-07:00</published>
    <updated>2011-06-19T00:00:00-07:00</updated>
    <link href="/2011/6/19/reliable-zeromq-pub-sub" rel="alternate" type="text/html"/>
    <title>Reliable ZeroMQ Pub Sub</title>
<content type="html">
&lt;p&gt;After Friday's &lt;a href=&quot;http://techno-weenie.net/2011/6/17/zeromq-pub-sub/&quot;&gt;ZeroMQ Pub Sub post&lt;/a&gt;, Jérôme Petazzoni &lt;a href=&quot;http://twitter.com/jpetazzo/status/81777168979468290&quot;&gt;taught
me a bit more about ZeroMQ&lt;/a&gt;.&lt;/p&gt;

&lt;!-- http://twitter.com/jpetazzo/status/81777168979468290 --&gt;


&lt;p&gt; &lt;style type='text/css'&gt;.bbpBox81777168979468290 {background:url(http://a3.twimg.com/profile_background_images/22130819/twi.png) #000000;padding:20px;} p.bbpTweet{background:#fff;padding:10px 12px 10px 12px;margin:0;min-height:48px;color:#000;font-size:18px !important;line-height:22px;-moz-border-radius:5px;-webkit-border-radius:5px} p.bbpTweet span.metadata{display:block;width:100%;clear:both;margin-top:8px;padding-top:12px;height:40px;border-top:1px solid #fff;border-top:1px solid #e6e6e6} p.bbpTweet span.metadata span.author{line-height:19px} p.bbpTweet span.metadata span.author img{float:left;margin:0 7px 0 0px;width:38px;height:38px} p.bbpTweet a:hover{text-decoration:underline}p.bbpTweet span.timestamp{font-size:12px;display:block}&lt;/style&gt; &lt;div class='bbpBox81777168979468290'&gt;&lt;p class='bbpTweet'&gt;@&lt;a class=&quot;tweet-url username&quot; href=&quot;http://twitter.com/technoweenie&quot; rel=&quot;nofollow&quot;&gt;technoweenie&lt;/a&gt; Once a PUB/SUB socket is connected, it &lt;em&gt;IS&lt;/em&gt; reliable. Use socket identity to be sure not to lose any message on reconnects.&lt;span class='timestamp'&gt;&lt;a title='Fri Jun 17 17:36:11 +0000 2011' href='http://twitter.com/jpetazzo/status/81777168979468290'&gt;less than a minute ago&lt;/a&gt; via web &lt;a href='http://twitter.com/intent/favorite?tweet_id=81777168979468290'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/favorite.png' /&gt; Favorite&lt;/a&gt; &lt;a href='http://twitter.com/intent/retweet?tweet_id=81777168979468290'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/retweet.png' /&gt; Retweet&lt;/a&gt; &lt;a href='http://twitter.com/intent/tweet?in_reply_to=81777168979468290'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/reply.png' /&gt; Reply&lt;/a&gt;&lt;/span&gt;&lt;span class='metadata'&gt;&lt;span class='author'&gt;&lt;a href='http://twitter.com/jpetazzo'&gt;&lt;img src='http://a2.twimg.com/profile_images/65895691/avatar_normal.jpg' /&gt;&lt;/a&gt;&lt;strong&gt;&lt;a href='http://twitter.com/jpetazzo'&gt;Jérôme Petazzoni&lt;/a&gt;&lt;/strong&gt;&lt;br/&gt;jpetazzo&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt; &lt;!-- end of tweet --&gt;&lt;/p&gt;

&lt;p&gt;Wow, so even ZeroMQ PUB sockets queue messages to subscribers.  It looks
like they get buffered in memory.  You can configure the &lt;a href=&quot;http://api.zeromq.org/2-1-1:zmq-setsockopt#toc3&quot;&gt;&lt;code&gt;ZMQ_HWM&lt;/code&gt;
option&lt;/a&gt; (&lt;code&gt;ZMQ::HWM&lt;/code&gt; in ruby) to limit how many messages will be buffered.  You can
also set the &lt;a href=&quot;http://api.zeromq.org/2-1-1:zmq-setsockopt#toc4&quot;&gt;&lt;code&gt;ZMQ_SWAP&lt;/code&gt; option&lt;/a&gt; to set the size of an on-disk
swap for messages that cross the high water mark.&lt;/p&gt;

&lt;p&gt;Armed with this bit of knowledge, I updated the &lt;a href=&quot;https://gist.github.com/1031540#file_pub.rb&quot;&gt;publisher
script&lt;/a&gt; to set an identity of &lt;code&gt;channel-username&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;chan&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PUB&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setsockopt&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;IDENTITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;tcp://*:5555&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;To really highlight reliable pub/sub, I wrote a &lt;a href=&quot;https://gist.github.com/1031540#file_pinger.rb&quot;&gt;custom publisher
script&lt;/a&gt;
that just pings every second.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;zmq&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PUB&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setsockopt&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;IDENTITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ping-pinger&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;tcp://*:5555&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;kp&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ping pinger &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href=&quot;https://gist.github.com/1031540#file_sub.rb&quot;&gt;Updating the subscriber&lt;/a&gt; should've been just as simple, but the &lt;code&gt;while&lt;/code&gt;
statement didn't allow for good error handling:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gets&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip!&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Any interruption in the process would lose a single message.  I instead
used a method:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@socket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recv&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;#&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SignalException&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This way any exception doesn't interrupt the processing of a message.
Here's what the loop looks like now:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;subscriber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Subscriber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;subscriber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;tcp://127.0.0.1:5555&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;subscriber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subscribe_to&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rubyonrails&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ruby-lang&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ping&amp;#39;&lt;/span&gt;

&lt;span class=&quot;kp&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subscriber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;subscriber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Quitting...&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This is what the console output looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#ping [pinger]: 21
#ping [pinger]: 22
^CQuitting...
ruby-1.9.2-p180 ~p/zcollab/pubsub git:(master) ✗$ ruby sub.rb abc
#ping [pinger]: 23
#ping [pinger]: 24
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I still run into rare cases where the Interrupt is raised inside the
&lt;code&gt;socket.recv&lt;/code&gt; call.  For a more advanced script, you could also try
&lt;a href=&quot;http://www.igvita.com/2008/07/22/unix-signals-for-live-debugging/&quot;&gt;trapping signals&lt;/a&gt; to control how your script exits.&lt;/p&gt;

&lt;p&gt;You can comment on this through the &lt;a href=&quot;http://news.ycombinator.com/item?id=2671372&quot;&gt;HN discussion&lt;/a&gt;...&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2011:6:17:zeromq-pub-sub</id>
    <published>2011-06-17T00:00:00-07:00</published>
    <updated>2011-06-17T00:00:00-07:00</updated>
    <link href="/2011/6/17/zeromq-pub-sub" rel="alternate" type="text/html"/>
    <title>ZeroMQ Pub Sub... How does it work?</title>
<content type="html">
&lt;p&gt;I read &lt;a href=&quot;http://robots.thoughtbot.com/post/6325247416/redis-pub-sub-how-does-it-work&quot;&gt;Nick Quaranto's blog post about Redis Pub
Sub&lt;/a&gt;, and thought I'd port the examples to ZeroMQ to
show how easy it is.  As I've said in previous posts, ZeroMQ is a great
networking library, and pub/sub is one of the patterns you can use.&lt;/p&gt;

&lt;p&gt;Redis is amazing though.  I'm not trying to say anything bad about
Nick's approach (and &lt;a href=&quot;http://radishapp.com/&quot;&gt;Radish&lt;/a&gt; is really awesome).  Why would you use ZeroMQ over Redis?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want to do quick messaging between hosts, processes, or even
threads.&lt;/li&gt;
&lt;li&gt;You want to use a different transport besides TCP: multicast,
in-process, inter-process.  The code doesn't change (besides the
bind/connect calls).&lt;/li&gt;
&lt;li&gt;You want to take advantage of other ZeroMQ messaging patterns to
(request/reply, push/pull, etc).&lt;/li&gt;
&lt;li&gt;You don't want certain components to talk to the central Redis
servers.&lt;/li&gt;
&lt;li&gt;You don't want to deal with connection errors.  ZeroMQ publishers and
subscribers can start up in any order.  They'll connect and reconnect
behind the scenes.&lt;/li&gt;
&lt;li&gt;ZeroMQ PUB sockets will buffer messages if a SUB socket
drops and reconnects.  Read more about &lt;a href=&quot;/2011/6/19/reliable-zeromq-pub-sub/&quot;&gt;reliable pub sub&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Why would you use Redis over ZeroMQ?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You &lt;em&gt;only&lt;/em&gt; need pub/sub, you have Redis already.  Fewer networking
components is obviously simpler and better.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;At GitHub, we use a lot of Redis, but we have one clear case where
ZeroMQ would be better suited: our
Service Hooks server.  Since the code is &lt;a href=&quot;https://github.com/github/github-services&quot;&gt;open source&lt;/a&gt;, the server it runs on is completely isolated from everything else.  We could setup another Redis server, but it's overkill just to enable message passing between the main GitHub app and the Services app.  We currently use HTTP calls, but could just as easily use ZeroMQ.&lt;/p&gt;

&lt;h2&gt;Demo&lt;/h2&gt;

&lt;p&gt;I ported Nick's code to a simple &lt;a href=&quot;https://gist.github.com/1031540&quot;&gt;ZeroMQ chat demo&lt;/a&gt;.  It works the same:  A user connects and publishes messages to a channel, and subscribed users receive them.&lt;/p&gt;

&lt;h2&gt;Publish&lt;/h2&gt;

&lt;p&gt;This uses the zmq gem to bind a SUB socket to port 5555.  You can tweak
this to play with some of the other network transports too, like
multicast or inproc.  I'm not using JSON in this example, though it is
of course possible with ZeroMQ.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# pub.rb&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;zmq&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;chan&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PUB&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;tcp://*:5555&amp;#39;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gets&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip!&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;One slight difference here is that the channel is sent as part of the
message.  Redis lets you send the channel as a separate parameter, but
ZeroMQ just includes it in the beginning of the message.&lt;/p&gt;

&lt;p&gt;You can run the script the same too:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ruby pub.rb rubyonrails technoweenie
Hello world
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This sends a ZeroMQ message like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rubyonrails technoweenie Hello World
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Subscribe&lt;/h2&gt;

&lt;p&gt;Now, let's write something to receive and display these published
messages.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# sub.rb&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;zmq&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;chans&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%w(rubyonrails ruby-lang)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sub&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SUB&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;tcp://127.0.0.1:5555&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;chans&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setsockopt&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ZMQ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SUBSCRIBE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recv&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;#&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;ZeroMQ is a c++ library built just for messaging, so it hides away the
complexities of receiving them behind the blocking &lt;code&gt;recv&lt;/code&gt; call.
Therefore, you don't have to worry about setting up callbacks for
&lt;code&gt;message&lt;/code&gt; events or anything like that, unless you use an asynchronous
ZeroMQ library (EventMachine, Node.js, etc).&lt;/p&gt;

&lt;p&gt;This works exactly like the Redis example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ruby pub.rb rubyonrails qrush
Whoa!
`rake routes` right?

$ ruby pub.rb rubyonrails turbage
How do I list routes?
Oh, duh. thanks bro.

$ ruby pub.rb ruby-lang qrush
I think it's Array#include? you really want.

$ ruby sub.rb
#rubyonrails - [qrush]: Whoa!
#rubyonrails - [turbage]: How do I list routes?
#ruby-lang - [qrush]: I think it's Array#include? you really want.
#rubyonrails - [qrush]: `rake routes` right?
#rubyonrails - [turbage]: Oh, duh. thanks bro.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Advanced Pub/Sub&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://news.ycombinator.com/user?id=sustrik&quot;&gt;sustrik&lt;/a&gt; on HN &lt;a href=&quot;http://news.ycombinator.com/item?id=2665824&quot;&gt;mentioned&lt;/a&gt; a
whitepaper on forwarding subscriptions through the network.  Check out
the &lt;a href=&quot;http://www.250bpm.com/pubsub&quot;&gt;Design of PUB/SUB subsystem in ØMQ&lt;/a&gt; whitepaper for a
look at a larger pub/sub architecture.&lt;/p&gt;

&lt;p&gt;If this sounds interesting to you, check out &lt;a href=&quot;http://www.rubyinside.com/why-rubyists-should-care-about-messaging-a-high-level-intro-5017.html&quot;&gt;Jakub Stastny's post: &quot;Why Rubyists Should Care About Messaging&quot;&lt;/a&gt;.  If you're hungry for more after that, the &lt;a href=&quot;http://zguide.zeromq.org/page:all&quot;&gt;ZeroMQ Guide&lt;/a&gt; goes into way more detail.  It's very well done, but might create an obsession around messaging :)&lt;/p&gt;

&lt;p&gt;You can comment on this through the &lt;a href=&quot;http://news.ycombinator.com/item?id=2665824&quot;&gt;HN discussion&lt;/a&gt;...&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2011:6:7:dropbear</id>
    <published>2011-06-07T00:00:00-07:00</published>
    <updated>2011-06-07T00:00:00-07:00</updated>
    <link href="/2011/6/7/dropbear" rel="alternate" type="text/html"/>
    <title>Dropbear: Dropbox 'clone'</title>
<content type="html">
&lt;p&gt;After reading the &lt;a href=&quot;http://zguide.zeromq.org/page:all&quot;&gt;ZeroMQ guide&lt;/a&gt; several times, I really wanted to hack on
a non trivial app.  Somehow I settled on a deceptively simple Dropbox
clone.  Though, I say &quot;clone&quot; not because I want to move my content off
Dropbox.  It's a simple way to describe the kind of system I'm
attempting to build.&lt;/p&gt;

&lt;p&gt;Here's the source to &lt;a href=&quot;https://gist.github.com/122849a52c5b33c5d890&quot;&gt;DropBear&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's more of a gross hack, as my dev process had to be greatly
accelerated to be ready for tonight's Riak meetup.  Clearly I shouldn't tell my
half-baked ideas to Mark Phillips (of Basho).  Only the fully baked
ones.  I have some &lt;a href=&quot;http://dl.dropbox.com/u/3561619/talks/zeromq-riak-technoweenie.pdf&quot;&gt;slides&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Essentially, DropBear clients push their files to a DropBear server
using ZeroMQ PUSH/PULL sockets.  The server dumps the file in Riak and
notifies other clients.  The server using PUB/SUB sockets to distribute
the changes to other clients.  I basically copied the &lt;a href=&quot;http://mongrel2.org/static/mongrel2-manual.html#x1-670005.3&quot;&gt;high level ZeroMQ
architecture&lt;/a&gt; that
mongrel2 uses.&lt;/p&gt;

&lt;p&gt;I made two critical errors in writing the DropBear prototype:&lt;/p&gt;

&lt;p&gt;First, I originally tried to get the clients and the server to talk through
ZeroMQ ROUTER sockets.  It &lt;em&gt;almost&lt;/em&gt; worked, but I ran into some weird
issues.  I ended up having
to redesign and rewrite DropBear to use the PUSH/PULL and PUB/SUB
sockets.  Luckily, I met some &lt;a href=&quot;http://www.dotcloud.com/&quot;&gt;dotcloud&lt;/a&gt; devs at the
Riak meetup (who use a ton of ZeroMQ).  They explained why my
understanding of ROUTER sockets was completely wrong.&lt;/p&gt;

&lt;p&gt;Second, I used EventMachine.  The ZeroMQ bindings work well, but the callback
structure was awkward.  I went with EM because I really wanted the
the clients and server to be single processes each.  I actually tried
using the Node.js bindings originally, but ran into what looks like a bug
with the PUB/SUB sockets.  So, I had to port it to EM.  However, most of
the examples in the guide are tiny scripts that work a single socket.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://zguide.zeromq.org/rb:wuserver&quot;&gt;Weather update server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://zguide.zeromq.org/rb:wuclient&quot;&gt;Weather update client&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Those ruby examples translate really closely to other languages too
(&lt;a href=&quot;http://zguide.zeromq.org/c:wuserver&quot;&gt;c&lt;/a&gt;,
&lt;a href=&quot;http://zguide.zeromq.org/lua:wuserver&quot;&gt;lua&lt;/a&gt;, &lt;a href=&quot;http://zguide.zeromq.org/py:wuserver&quot;&gt;python&lt;/a&gt;).
Even the node.js bindings are &lt;a href=&quot;http://zguide.zeromq.org/js:wuserver&quot;&gt;fairly&lt;/a&gt; &lt;a href=&quot;http://zguide.zeromq.org/js:wuclient&quot;&gt;close&lt;/a&gt;
(though the blocking &lt;code&gt;recv&lt;/code&gt; call is replaced by emitted &lt;code&gt;message&lt;/code&gt; events).  I
love how each script is so tiny, and describes its exact function in a
small comment at the top of the file.&lt;/p&gt;

&lt;p&gt;It's not so much that the EventMachine bindings are bad, but it feels
like this is how ZeroMQ is meant to be used.  Talking with &lt;a href=&quot;https://twitter.com/#!/sebp&quot;&gt;Sebastien&lt;/a&gt;
(from dotcloud) confirmed it.  Lots of tiny scripts that use ZeroMQ
messages the way Erlang uses messages to communicate.&lt;/p&gt;

&lt;p&gt;As a project, DropBear is pretty much a failure right now.  But the experience
building it taught me a lot about how ZeroMQ should work.  It's always
fun to play around in new environments, especially when they challenge
the way you think about writing code.&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2011:5:22:zeromq-basics</id>
    <published>2011-05-22T00:00:00-07:00</published>
    <updated>2011-05-22T00:00:00-07:00</updated>
    <link href="/2011/5/22/zeromq-basics" rel="alternate" type="text/html"/>
    <title>ZeroMQ Basics</title>
<content type="html">
&lt;p&gt;A few weeks ago, I had one of those sleepless nights that comes with
travelling several timezones ahead of what you're used to.  I picked the
&lt;a href=&quot;http://zguide.zeromq.org/page:all&quot;&gt;ZeroMQ (ØMQ) Guide&lt;/a&gt; as reading material to lull me into a deep sleep.  Bad
move: I had a &lt;strong&gt;Bing&lt;/strong&gt; moment with ØMQ, and stayed up playing with network
services on my laptop until it was time for my son to go to school the next
day.&lt;/p&gt;

&lt;p&gt;I have to admit, the name &quot;ZeroMQ&quot; was a little misleading for me.  I think
that's because most other message queues are very similar: something
pushes messages into a big, centralized queue, and workers pop
messages off the front.  ØMQ is really just a networking library.
Sockets the way you want them to work.  I think Zed Shaw put it best in
his &lt;a href=&quot;http://blip.tv/pycon-us-videos-2009-2010-2011/pycon-2011-advanced-network-architectures-with-zeromq-4896861&quot;&gt;Pycon talk&lt;/a&gt;: ØMQ can replace your internal HTTP REST
services.  HWhaaat?!?&lt;/p&gt;

&lt;h2&gt;First, a Quick Primer&lt;/h2&gt;

&lt;p&gt;ZeroMQ is a c++ library providing asynchronous messaging over a variety
of transports (inproc, IPC, TCP, OpenPGM, etc).  It has bindings for
over 20 languages.  ØMQ has simple socket patterns that can be used
together to build more complex architectures.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request and Reply sockets are the simplest type, providing synchronous
messaging between two systems.&lt;/li&gt;
&lt;li&gt;Push and Pull sockets let you distribute messages to multiple workers.
A Push socket will distribute sent messages to its Pull clients evenly.&lt;/li&gt;
&lt;li&gt;Publish sockets broadcast messages to any Subscribe sockets that may be listening.&lt;/li&gt;
&lt;li&gt;Dealer and Router sockets (or &lt;code&gt;X_REP&lt;/code&gt;/&lt;code&gt;X_REQ&lt;/code&gt; in older versions of
ØMQ) handle asynchronous messaging.  They require a bit of knowledge
of ØMQ addressing to really grok.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Replacing REST&lt;/h2&gt;

&lt;p&gt;When you're designing large systems, it makes sense to break things out
into smaller pieces that communicate across some common protocol.  A lot
of people champion the REST/JSON combo because it's easy, it works well,
and it's available &lt;em&gt;everywhere&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;ØMQ is like that too.  It works nearly the same in every supported
language.  You can use JSON, MessagePack, &lt;a href=&quot;http://tnetstrings.org/&quot;&gt;tagged netstrings&lt;/a&gt;,
etc.  You get cool socket types that aren't really possible with REST
(pub/sub, push/pull).&lt;/p&gt;

&lt;p&gt;You do end up having to build your own protocol a bit.  You end up
losing the richness of HTTP (verbs, URIs, headers).  You're also unable
to expose these services outside your private network due to some
asserts in the ØMQ code.&lt;/p&gt;

&lt;h2&gt;Dakee: the Request/Reply Chat&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/technoweenie/zcollab/blob/master/dakee.js&quot;&gt;Dakee&lt;/a&gt; is a simple chat bot that uses REQ and REP sockets to
communicate with another user.  The names come from
&lt;a href=&quot;http://collabedit.com/&quot;&gt;Collabedit&lt;/a&gt;, which is what &lt;a href=&quot;https://github.com/towski&quot;&gt;Towski&lt;/a&gt; and I used to
write the initial versions.&lt;/p&gt;

&lt;p&gt;The script binds a REP socket to 5555, and connects a REQ socket to the
other user's REP socket.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;zeromq&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createSocket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;req&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rep&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createSocket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;rep&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ip&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;CLIENT_IP&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;192.168.1.25&amp;#39;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;tcp://&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;:5555&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bindSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;tcp://*:5555&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Received messages are printed to standard output.  Messages from
standard input are sent out on the REP socket if it needs a response, or
to the REQ socket.&lt;/p&gt;

&lt;p&gt;It makes for an unusually useless private chat system, but it manages to
highlight the behavior of the REQ and REP sockets pretty well.  The
node.js event loop actually works against ØMQ in this case, allowing you
to send multiple messages to the REQ socket.  However, the other client
won't see these extra messages until they've replied to your first one.&lt;/p&gt;

&lt;p&gt;Why is the REQ/REP pair of socket types synchronous like this?  One
factor is simplicity.  The REP socket keeps you from having to know
which REQ socket it needs to reply to.  If you want more flexibility,
you'll have to look at the Dealer and Router socket types.&lt;/p&gt;

&lt;h2&gt;ZeroMQ in the Wild&lt;/h2&gt;

&lt;p&gt;The only projects I know of that use ØMQ are &lt;a href=&quot;http://mongrel2.org/home&quot;&gt;Mongrel2&lt;/a&gt;
and &lt;a href=&quot;http://tech.backtype.com/preview-of-storm-the-hadoop-of-realtime-proce&quot;&gt;Storm&lt;/a&gt;.  Mongrel2 is a web server that uses ZeroMQ to talk to
backend handlers written in &lt;a href=&quot;http://mongrel2.org/home#languages&quot;&gt;any language&lt;/a&gt;.
Storm is still vaporware, but it sounds like it uses ØMQ in a similar
fashion.&lt;/p&gt;

&lt;h2&gt;What next?&lt;/h2&gt;

&lt;p&gt;I'm continually amazed at the wealth of information in the &lt;a href=&quot;http://zguide.zeromq.org/page:all&quot;&gt;ZeroMQ
Guide&lt;/a&gt;.  I'd highly recommend checking it out if you want a new
perspective on message queue systems.  The code examples are mostly in
c, but each lists ported examples in other languages.  If a language
gets all of the samples ported, it is awarded with a full translation
(so far only PHP and Lua have succeeded).  I'd love to see full Ruby and
Node.js translations too (I took the easy ones, sorry!).  Porting these
examples are a great way to figure out how ØMQ works.&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2011:4:28:my-put-requests-bug-me</id>
    <published>2011-04-28T00:00:00-07:00</published>
    <updated>2011-04-28T00:00:00-07:00</updated>
    <link href="/2011/4/28/my-put-requests-bug-me" rel="alternate" type="text/html"/>
    <title>My PUT Requests Bug Me</title>
<content type="html">
&lt;p&gt;So here I am, writing documentation for some new &lt;a href=&quot;http://developer.github.com&quot;&gt;GitHub API sweetness&lt;/a&gt;, when
something strikes me.  Why are we using PUT requests for updates?
Should it bug me that my API uses the PUT verb?&lt;/p&gt;

&lt;h2&gt;The Conventional Wisdom&lt;/h2&gt;

&lt;p&gt;I was actively contributing to the Rails Core team when Rails had its &lt;a href=&quot;http://weblog.rubyonrails.org/2007/1/19/rails-1-2-rest-admiration-http-lovefest-and-utf-8-celebrations&quot;&gt;sweaty
HTTP lovefest&lt;/a&gt; in Rails v1.2.x.  This introduced the REST concepts to a lot of Rails developers in a real applicable form.  Not only &lt;em&gt;can&lt;/em&gt; I build a sweet REST service, it's provided for me as long as I stay on the golden path... Huzzah!&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PostsController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# PUT /posts/1.json&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;respond_to&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@post&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This wasn't an accident.  David (and the rest of us) were all heavily inspired
by the Atom Publishing Protocol.  Look at how they specify &lt;a href=&quot;http://bitworking.org/projects/atom/rfc5023.html#edit&quot;&gt;updates to
resources&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Client                                     Server
  |                                           |
  |  1.) PUT to Member URI                    |
  |      Member Representation                |
  |------------------------------------------&amp;gt;|
  |                                           |
  |  2.) 200 OK                               |
  |&amp;lt;------------------------------------------|
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It's a simplistic flow chart, but it clearly shows how PUT requests are
used to update the resources.  Joe Gregorio (one of the AtomPub
creators) used a similar setup for &lt;a href=&quot;http://bitworking.org/news/RESTLog_Specification&quot;&gt;RESTLog&lt;/a&gt;.
&lt;a href=&quot;http://bitworking.org/news/RESTLog_Overview&quot;&gt;RESTLog is a blogging system&lt;/a&gt; that stored posts as &lt;code&gt;&amp;lt;item&amp;gt;&lt;/code&gt; RSS fragments.
At the time, I didn't really understand what REST meant, I was more
focused in &lt;a href=&quot;http://diveintomark.org/archives/2004/02/04/incompatible-rss&quot;&gt;trying to get RSS to work&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Mixed Messages&lt;/h2&gt;

&lt;p&gt;I think this is where things got confused.  AtomPub and RESTLog assume
you're using the PUT verb to replace the contents of the resource on
every request.  However, typical API updates don't require the full XML
or JSON data.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;POST /items
{&quot;title&quot;: &quot;a&quot;, &quot;body&quot;: &quot;b&quot;}

PUT /items/1
{&quot;title&quot;: &quot;a!&quot;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What does &lt;a href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html&quot;&gt;RFC 2616&lt;/a&gt; say about this?&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity... In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Section 9.6 doesn't really mention partial updates anywhere.  It mainly
says that PUT requests are idempotent, and uses the URL to identify the
resource.  So who says PUT is for complete replacements only?
&lt;a href=&quot;http://tools.ietf.org/html/rfc5789&quot;&gt;RFC 5789&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;In a PUT request, the enclosed entity
is considered to be a modified version of the resource stored on the
origin server, and the client is requesting that the stored version
be &lt;strong&gt;replaced&lt;/strong&gt;.  With PATCH, however, the enclosed entity contains a set
of instructions describing how a resource currently residing on the
origin server &lt;strong&gt;should be modified to produce a new version&lt;/strong&gt;.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/mnot/status/63787616394428417&quot;&gt;Mark Nottingham just pointed me&lt;/a&gt;
towards a new draft of the HTTP Message
Semantics RFC (written just a few days ago!).  It actually mentions
partial PUT requests:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;An origin server SHOULD reject any PUT request that contains a
Content-Range header field, since it might be misinterpreted as
partial content (or might be partial content that is being mistakenly
PUT as a full representation).  Partial content updates are possible
by targeting a separately identified resource with state that
overlaps a portion of the larger resource, or by using a different
method that has been specifically defined for partial updates (for
example, the PATCH method defined in &lt;a href=&quot;http://tools.ietf.org/html/rfc5789&quot;&gt;RFC5789&lt;/a&gt;).&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;So in summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PUT and Content-Range don't mix (sorry &lt;a href=&quot;http://twitter.com/seancribbs/status/63222431971688449&quot;&gt;Sean&lt;/a&gt;!)&lt;/li&gt;
&lt;li&gt;Partial PUTs can target internal resources.  For instance, you could
update a user's address by making a PUT request to the user's address
resource.&lt;/li&gt;
&lt;li&gt;Or, use PATCH.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Should I Care?&lt;/h2&gt;

&lt;p&gt;In my &lt;a href=&quot;http://twitter.com/technoweenie/status/63203978145579009&quot;&gt;adhoc Twitter poll&lt;/a&gt;, the responses I got were divided by those
saying I should care (and use PATCH), or asking what was wrong with PUT.&lt;/p&gt;

&lt;p&gt;I've dealt with a lot of API bugs, and I can only think of a single one
that had to do with the PUT verb specifically: Browsers can only send
GET or POST requests.  Depending on the server, user agents can work
around this by using POST and specifying the &quot;real&quot; verb with a
&lt;a href=&quot;https://github.com/rack/rack/blob/master/lib/rack/methodoverride.rb&quot;&gt;&lt;code&gt;_method&lt;/code&gt; parameter&lt;/a&gt; or the &lt;a href=&quot;http://code.google.com/apis/gdata/docs/2.0/basics.html&quot;&gt;&lt;code&gt;X-HTTP-Method-Override&lt;/code&gt; header&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At some point, all this POST vs PUT nonsense devolves into spec wankery
anyway.  Does it really hurt anyone that certain API endpoints expect
the PUT verb?  Not really.  People are still able to ship cool shit.  It
doesn't really matter to most people if you &lt;a href=&quot;http://developer.rdio.com/blog/read/No_REST_for_the_wicked&quot;&gt;call your RPC API a REST
API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, I've been working on GitHub API v3 as a clean slate.  It gave
me a chance to infuse more REST concepts into everything.  So, I weighed my
options.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many users will be affected?&lt;/li&gt;
&lt;li&gt;What's the chance that they will update their code to match changes to
the API?&lt;/li&gt;
&lt;li&gt;Is there an easy way to maintain backwards compatibility?&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Fortunately, API v3 documentation was only given out to a few eager beta
testers.  So, I knew right away that the number of users was small, with
a high probability that they'd notice changes and update their code
accordingly.  I really wanted to avoid the case where I break some old
script on a server somewhere, that no one remembers the login info for.&lt;/p&gt;

&lt;p&gt;In this specific case, I also had a way to keep the old behavior.  I
hacked up a &lt;a href=&quot;https://gist.github.com/e73ef466841e7769b48e&quot;&gt;quick Sinatra extension&lt;/a&gt;
to let me easily define actions that respond to multiple verbs.  I also
spoke with the Sinatra team in &lt;a href=&quot;https://github.com/sinatra/sinatra/issues/253&quot;&gt;adding this to Sinatra itself&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I launched the &lt;a href=&quot;https://github.com/blog/846-new-issues-and-gist-api&quot;&gt;new GitHub API&lt;/a&gt; this morning, and
I'm pretty happy with how it turned out.  It's clear that what we have
is just enough for people to be productive in, and there's still some
more work to be done fine tuning things.&lt;/p&gt;

&lt;p&gt;The next big thing I want to tackle on the GitHub API is &lt;a href=&quot;http://en.wikipedia.org/wiki/HATEOAS&quot;&gt;HATEOAS&lt;/a&gt;.
I already dipped my toe in those waters for the &lt;a href=&quot;https://help.tenderapp.com/kb/api/introduction&quot;&gt;Tender Support
API&lt;/a&gt;...&lt;/p&gt;

&lt;h2&gt;And Now, Your Moment of Zen&lt;/h2&gt;

&lt;p&gt;Here's the &lt;a href=&quot;http://webmachine.basho.com/diagram.html&quot;&gt;full diagram&lt;/a&gt; of
the flow that determines how &lt;a href=&quot;http://webmachine.basho.com/&quot;&gt;webmachine&lt;/a&gt; processes resources.  Webmachine
is the framework that powers &lt;a href=&quot;http://wiki.basho.com/REST-API.html&quot;&gt;Riak's HTTP API&lt;/a&gt;, among other things.&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2010:10:5:nub-nub</id>
    <published>2010-10-05T00:00:00-07:00</published>
    <updated>2010-10-05T00:00:00-07:00</updated>
    <link href="/2010/10/5/nub-nub" rel="alternate" type="text/html"/>
    <title>Nub Nub: PubSubHubbub protocol implementation</title>
<content type="html">
&lt;p&gt;I've been toying around with the idea of adding a PubSubHubbub layer around the GitHub timeline events, so I wrote &lt;a href=&quot;http://github.com/technoweenie/nubnub&quot;&gt;Nub Nub&lt;/a&gt;.  Nub Nub is a bare implementation of PubSubHubbub so I can explore how it might be used inside GitHub.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;http://techno-weenie.net/images/2010/10/ewok.jpeg&quot; /&gt;
&lt;/center&gt;


&lt;p&gt;PubSubHubbub (PuSH) is &quot;a simple, open, web-hook-based pubsub protocol,&quot; according to the &lt;a href=&quot;http://code.google.com/p/pubsubhubbub/&quot;&gt;homepage&lt;/a&gt;.  There's a lot of talk about hub discovery URLs, Atom feeds, multicast publishing, etc.  Let's boil it all down to the essentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A feed (or PuSH topic) identifies one or more hub servers.&lt;/li&gt;
&lt;li&gt;A subscriber (a webhook server) subscribes to one or more topics.&lt;/li&gt;
&lt;li&gt;When the feed updates, it pings the hub server.&lt;/li&gt;
&lt;li&gt;The hub server then publishes the data to the subscribers.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;As far as GitHub goes, this is still too complex.  We're not a big feed aggregation service, or a generic PuSH hub service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A GitHub user specifies one or more post-receive URLs that get pinged on every Git push.&lt;/li&gt;
&lt;li&gt;GitHub publishes to these post-receive URLs on every Git push.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;It's the same thing, minus all the talk about feed scanning and updates.  We already have an internal queue system that can handle this.  We also have people asking for an API to manage service hooks and post receive URLs, so why not provide &lt;a href=&quot;http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.3.html#rfc.section.6.1&quot;&gt;standard API hooks&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;As far as Atom/RSS go, there's not a lot in the PuSH spec that really depend on them.  The feed scanning portion does, of course.  The data is all internal though, so there's no need to implement the &lt;a href=&quot;http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.3.html#rfc.section.7.1&quot;&gt;Content Notification&lt;/a&gt; methods.  But there's no sense in parsing our own feeds, so we can push straight JSON.  The specs do say that &lt;a href=&quot;http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.3.html#rfc.section.7.3&quot;&gt;published items need to be Atom or RSS&lt;/a&gt;, but I see no reason we can't support JSON.  If the subscriber subscribes to a JSON topic, the hub pushes JSON.  If the subscriber subscribes to an Atom topic, the hub pushes Atom.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;http://techno-weenie.net/images/2010/10/ewok-wookie-team.jpeg&quot; /&gt;
&lt;/center&gt;


&lt;p&gt;This strategy can be applied to any other web service that sends out notifications.  That's why I wrote Nub Nub.  It's a pretty bare bones implementation, with no mention of a preferred web server or data store.  It just provides a few methods for making or responding to PuSH calls.&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2010:8:3:protobuf-for-node</id>
    <published>2010-08-03T00:00:00-07:00</published>
    <updated>2010-08-03T00:00:00-07:00</updated>
    <link href="/2010/8/3/protobuf-for-node" rel="alternate" type="text/html"/>
    <title>Protocol Buffers with Riak for Node.js</title>
<content type="html">
&lt;p&gt;I've been playing around with &lt;a href=&quot;https://wiki.basho.com/display/RIAK/The+Riak+Fast+Track&quot;&gt;Riak&lt;/a&gt; a bit lately.  It's a simple key/value store with S3-style buckets and one-way links between keys.  It also has clustering built in, and lets you run map/reduce against a set of data pretty easily.  All this, over a simple HTTP API.&lt;/p&gt;

&lt;p&gt;It's a great way to start playing with Riak, but I found it to be pretty slow.  With Riak, there are two more options: use the Erlang client, or write a Protocol Buffer adapter.  I'd never done anything with &lt;a href=&quot;http://code.google.com/p/protobuf/&quot;&gt;Protocol Buffers&lt;/a&gt;, so I figured this was good opportunity.&lt;/p&gt;

&lt;h2&gt;Riak PBC Client&lt;/h2&gt;

&lt;p&gt;Armed with &lt;a href=&quot;http://code.google.com/p/protobuf-for-node/&quot;&gt;Node.js Protocol Buffer&lt;/a&gt; serializing and parsing abilities, I took a look at the &lt;a href=&quot;https://wiki.basho.com/display/RIAK/PBC+API&quot;&gt;Riak PBC API&lt;/a&gt;.  It has a very simple API:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;00 00 00 07 09 0A 01 62 12 01 6B
|----Len---|MC|----Message-----|
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each message starts with 4 bytes for the message length, a single byte for the message code, and then the message.&lt;/p&gt;

&lt;p&gt;The example above is how a simple request for a key might look.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// the Protocol Buffer schema.
message RpbGetReq {
    required bytes bucket = 1;
    required bytes key = 2;
    optional uint32 r = 3;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A Riak request looks something like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;Schema = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;protobuf_for_node&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Schema&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;schema = &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Schema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;./riak.desc&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;GetReq = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;RpbGetReq&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &amp;lt;Buffer 0a 01 62 12 01 6b&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;data = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;GetReq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;serialize&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bucket: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;key: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;k&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;len  = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# account for riak code too&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;req  = &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 4 byte message length&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;copy&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# copy serialized data to the buffer&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# req is now&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;lt;Buffer 00 00 00 07 09 0a 01 62 12 01 6b&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That assembles the message.  Now, we just create a tcp connection to send it to Riak:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;conn = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;net&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createConnection&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8087&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;connect&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Finally, something needs to listen for the data event for a response:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(chunk) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;len = &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; 
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
         &lt;span class=&quot;nx&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# subtract 1 for the message code&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;type = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lookup_type_from_code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;msg  = &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;copy&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;data = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Pooling Connections&lt;/h2&gt;

&lt;p&gt;My &lt;a href=&quot;http://gist.github.com/488488#file_riak.coffee&quot;&gt;initial example&lt;/a&gt; started off pretty basic, but started to grow out of control.  I quickly realized that since the socket API was very synchronous, I needed to implement a connection pool so a Node.js process could have simultaneous conversations with Riak.  A basic example looks like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;riak = &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;./protobuf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)()&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;server = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createServer&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(request, response) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# get a fresh connection off the pool&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;riak&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(conn) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# make a connection, call the given callback when it returns.&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;PingReq&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(data) -&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;writeHead&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;text/plain&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;finish&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# release the connection back to the pool&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# SHORTCUT&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;server = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createServer&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(request, response) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# automatically gets a fresh connection, sends a request, and releases&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# it back to the pool when done.&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;riak&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;PingReq&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(data) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;writeHead&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;text/plain&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;nori + riak-js&lt;/h2&gt;

&lt;p&gt;Right now, this isn't in any released version of nori or riak-js.  The rough Protocol Buffers client is available in &lt;a href=&quot;http://github.com/technoweenie/riak-js/blob/coffee/src/protobuf.coffee&quot;&gt;the coffee branch of my riak-js fork&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When Frank released the sweet &lt;a href=&quot;http://riakjs.org/&quot;&gt;Riak-JS site&lt;/a&gt;, I took a hard look at what purpose nori was solving:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I wanted to learn more about Riak (accomplished).&lt;/li&gt;
&lt;li&gt;I wanted to experiment with a new API style (very similar to Riak-js)&lt;/li&gt;
&lt;li&gt;I wanted a higher level Riak lib, more like an ORM.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The goals aligned pretty closely with riak-js, so there seemed no good reason to double our efforts.  I've decided to discontinue nori for the time being, and focus my Riak efforts in a refactoring of riak-js.  We want to have a single lib that lets you access Riak from jQuery (maybe), as well as Node.js over the HTTP and PBC APIs.&lt;/p&gt;

&lt;p&gt;So, what is the current progress of all this?  Here are some quick benchmarks from my iMac i7:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;coffeescript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# riak-js http API &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ab -n 5000 -c 20 &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 734.31 req/sec&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;sys  = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;sys&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;http = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;http&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;db   = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;riak-js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;server = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createServer&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(req, resp) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;airlines&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;KLM&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(flight, meta) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;writeHead&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;text/plain&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;flight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8124&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# riak-js PBC API&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ab -n 5000 -c 20&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 1682.01 req/sec&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;sys  = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;sys&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;http = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;http&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;riak = &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;./protobuf&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)()&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;server = &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createServer&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(req, resp) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;riak&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;GetReq&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bucket: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;airlines&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;key: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;KLM&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(flight) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;writeHead&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;text/plain&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;flight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8124&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That's over a 2x speedup, not bad.&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2010:7:13:in-process-node-queues</id>
    <published>2010-07-13T00:00:00-07:00</published>
    <updated>2010-07-13T00:00:00-07:00</updated>
    <link href="/2010/7/13/in-process-node-queues" rel="alternate" type="text/html"/>
    <title>In-Process Node.js Queues</title>
<content type="html">
&lt;p&gt;Node.js is great at handling lots of asynchronous connections, but sometimes I'd like to limit how many are in use.  One real world example is some kind of spider or feed reader.  If you have a list of 500 addresses to fetch, you don't want to fetch them all at once.  Maybe they're all on one server, or the requests return large files that need some post processing.&lt;/p&gt;

&lt;p&gt;A simple queue like Resque is great for this, but I wanted something even simpler.  Something that lived in the Node.js process, and could exit cleanly without any of that persistent mess left over.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/technoweenie/node-chain-gang&quot;&gt;Chain Gang&lt;/a&gt; is the result of my experimentation.  My idea is using the Node.js event system for pub/sub:&lt;/p&gt;

&lt;p&gt;First, I specify my unit of work.  In this case, I'm fetching a a web address, and calling worker.finish() after that's done.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;sys: &lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;sys&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;http: &lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;http&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;client: &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createClient&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# start an active chain gang queue with 3 workers by default.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;chain: &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;chain-gang&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# downloads a web page, runs the callback when it&amp;#39;s done.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;get_path: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(path, cb) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;req: &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;GET&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;host: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;response&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(resp) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(chunk) -&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;chunk&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;end&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cb&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# returns a chain gang job that downloads a web page and finishes the worker.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;job: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(timeout, name) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;(worker) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;get_path&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/$timeout/$name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;worker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;finish&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now, I can add the callback, and queue the unit of work:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;coffeescript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# queues the job&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# queues the job with the unique name &amp;quot;foo_request&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foo_request&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Assuming the chain gang queue is active, it should start executing the jobs immediately.&lt;/p&gt;

&lt;p&gt;There are two interesting behaviors that are possible now: Duplicate jobs are not run, and only a fixed number of jobs can run at any given time.  To highlight them, I have some sample files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/code/2010/7/chain-gang-sample/webserver.coffee&quot;&gt;webserver.coffee&lt;/a&gt; is a silly web server that waits for a specified amount of time before returning a request.  A URL like &quot;/3/foo&quot; will return in 3 seconds, for example.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/code/2010/7/chain-gang-sample/chain-with-dupes.coffee&quot;&gt;chain-with-dupes.coffee&lt;/a&gt; shows what happens when multiple jobs with the same name are queued.  In this contrived example, only the first, longer one is completed.  The rest are ignored.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/code/2010/7/chain-gang-sample/chain-with-uniques.coffee&quot;&gt;chain-with-uniques.coffee&lt;/a&gt; shows how Chain Gang handles more jobs than workers.  They just sit in an array until a free worker can take it.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;On a side note, this is my first lib using &lt;a href=&quot;http://npmjs.org/&quot;&gt;npm&lt;/a&gt; (Node.js package manager).  Type &lt;code&gt;npm install chain-gang&lt;/code&gt; to get rockin'.&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2010:7:7:geektalk-interview</id>
    <published>2010-07-07T00:00:00-07:00</published>
    <updated>2010-07-07T00:00:00-07:00</updated>
    <link href="/2010/7/7/geektalk-interview" rel="alternate" type="text/html"/>
    <title>Geek Talk Interview</title>
<content type="html">
&lt;p&gt;So, I was interviewed by &lt;a href=&quot;http://thegeektalk.com/interviews/rick-olson/&quot;&gt;The Geek Talk&lt;/a&gt; recently.  Read on to learn the awful truth behind my early programming days :)&lt;/p&gt;

&lt;p&gt;Also, I'm moving to San Francisco this weekend.  I'm really looking forward to working side by side with my fellow GitHubbers.  Portland's a great place, and I have a feeling I'll be back.&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2010:6:28:tee_and_child_processes</id>
    <published>2010-06-28T00:00:00-07:00</published>
    <updated>2010-06-28T00:00:00-07:00</updated>
    <link href="/2010/6/28/tee_and_child_processes" rel="alternate" type="text/html"/>
    <title>Tee and Child Processes</title>
<content type="html">
&lt;p&gt;My first node.js project at GitHub is a &lt;a href=&quot;http://github.com/blog/678-meet-nodeload-the-new-download-server&quot;&gt;replacement download server&lt;/a&gt;.  I wanted to remove the extra moving pieces required to get it to work.  One of the steps involves writing a file from the output of &lt;code&gt;git archive&lt;/code&gt;.  My initial attempt looked like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;fs: &lt;/span&gt;     &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;fs&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;child: &lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;child_process&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;git: &lt;/span&gt;    &lt;span class=&quot;nx&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spawn&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;git&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;archive&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;other options&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;stream: &lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createWriteStream&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;outputFilename&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# writes the file from git archive to the file stream&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(data) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# if the file stream isn&amp;#39;t flushed, pause git&amp;#39;s stdout&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pause&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# once the file stream is flushed, resume git&amp;#39;s stdout&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;drain&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resume&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;exit&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(code) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;However, git archive's tar format does not come compressed.  That means I have to pipe the output to another ChildProcess object.  How do I do that without a lot of code duplication?  I put the common callbacks into defined functions:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;fs: &lt;/span&gt;     &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;fs&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;child: &lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;child_process&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# writes data to the local file system.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;streamer: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(data) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pause&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# pipes the data to the gzip process.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;gzipper: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(data) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pause&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# closes the written file stream.  &lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;closer: &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;(code) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;git: &lt;/span&gt;    &lt;span class=&quot;nx&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spawn&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;git&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;archive&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;other options&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;stream: &lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createWriteStream&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;outputFilename&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;drain&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resume&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# if this is a tarball, pipe `git archive` through `gzip -n`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;outputFilename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/\.tar\.gz$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;gzip: &lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spawn&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;gzip&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-n&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;-c&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;input: &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdout&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;gzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;streamer&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;gzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt;        &lt;span class=&quot;s1&quot;&gt;&amp;#39;exit&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;closer&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;gzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt;  &lt;span class=&quot;s1&quot;&gt;&amp;#39;drain&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resume&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;exit&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(code) -&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;gzip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;input: &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdout&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;exit&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;closer&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gzipper&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;streamer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That's the code to write either &lt;code&gt;git archive --format=zip&lt;/code&gt; or &lt;code&gt;git archive --format=tar | gzip&lt;/code&gt; to a file.  It works, but the code is more complicated than I'd like.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/rtomayko&quot;&gt;Ryan&lt;/a&gt; suggested I use &lt;a href=&quot;http://man.cx/tee(1posix)&quot;&gt;tee&lt;/a&gt; for outputting the file, and /bin/sh to assemble the pipes.&lt;/p&gt;

&lt;p&gt;Now, the code is even simpler than my first attempt:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;coffeescript&quot;&gt;&lt;span class=&quot;nv&quot;&gt;child: &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;child_process&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;cmd: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;git archive ...&amp;#39;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;outputFilename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/\.tar\.gz$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39; | gzip -n -c&amp;#39;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;arch: &lt;/span&gt;   &lt;span class=&quot;nx&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spawn&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/bin/sh&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-c&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$cmd | tee $outputFilename&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;arch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;exit&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;(code) -&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# do something&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;




</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2010:6:23:you-can-let-go-now</id>
    <published>2010-06-23T00:00:00-07:00</published>
    <updated>2010-06-23T00:00:00-07:00</updated>
    <link href="/2010/6/23/you-can-let-go-now" rel="alternate" type="text/html"/>
    <title>You can let go now</title>
<content type="html">
&lt;p&gt;If you're reading this, I've completed migrating my blog from &lt;a href=&quot;http://github.com/technoweenie/mephisto&quot;&gt;Mephisto&lt;/a&gt;
to &lt;a href=&quot;http://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I had fun working on it, but clearly I failed on being able to foster a good community around it.  It was an unconventional Rails app in a time before things like Rack, Sinatra, MongoDB, restful controllers, etc.  It's nice to see similar ideas in newer projects though:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://get.harmonyapp.com/&quot;&gt;Harmony&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/creationix/wheat&quot;&gt;Wheat&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Thanks to everyone who &lt;a href=&quot;http://github.com/technoweenie/mephisto/contributors&quot;&gt;helped work on it&lt;/a&gt;, especially &lt;a href=&quot;http://alternateidea.com/&quot;&gt;Justin&lt;/a&gt; for the partnership on the design.  Mephisto was where our working relationship started, which eventually lead to Lighthouse and ENTP...&lt;/p&gt;

</content>
  </entry>

  <entry xml:base="http://techno-weenie.net/">
    <author>
      <name>rick</name>
    </author>
    <id>tag:techno-weenie.net,2010:5:17:railsconf-building-apis</id>
    <published>2010-05-17T00:00:00-07:00</published>
    <updated>2010-05-17T00:00:00-07:00</updated>
    <link href="/2010/5/17/railsconf-building-apis" rel="alternate" type="text/html"/>
    <title>Railsconf: Building APIs</title>
<content type="html">
&lt;p&gt;I'm going to be taking Chris' place in the &lt;a href=&quot;http://en.oreilly.com/rails2010/public/schedule/detail/14502&quot;&gt;Building an API&lt;/a&gt; panel at Railsconf in June.  I'll be speaking about the GitHub API (of course), as well as touching on my experiences building APIs for Lighthouse and Tender.&lt;/p&gt;

&lt;p&gt;Don't despair, Chris will still be doing his &lt;a href=&quot;http://en.oreilly.com/rails2010/public/schedule/detail/14595&quot;&gt;Redis, Rails, and  Reque&lt;/a&gt; talk.&lt;/p&gt;

</content>
  </entry>

</feed>

