<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>NIL: .to write(1) ~ help:about</title>
	<atom:link href="http://tech.blog.aknin.name/feed/" rel="self" type="application/rss+xml" />
	<link>http://tech.blog.aknin.name</link>
	<description>Glossolalia about technology by @aknin</description>
	<lastBuildDate>Tue, 14 Feb 2012 09:07:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='tech.blog.aknin.name' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://0.gravatar.com/blavatar/488efa50a3512ade2d4fd7910a778a2c?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>NIL: .to write(1) ~ help:about</title>
		<link>http://tech.blog.aknin.name</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://tech.blog.aknin.name/osd.xml" title="NIL: .to write(1) ~ help:about" />
	<atom:link rel='hub' href='http://tech.blog.aknin.name/?pushpress=hub'/>
		<item>
		<title>RESTfully atomically incrementing a counter using HTTP PATCH</title>
		<link>http://tech.blog.aknin.name/2012/02/08/restfully-atomically-incrementing-a-counter-using-http-patch/</link>
		<comments>http://tech.blog.aknin.name/2012/02/08/restfully-atomically-incrementing-a-counter-using-http-patch/#comments</comments>
		<pubDate>Wed, 08 Feb 2012 13:38:06 +0000</pubDate>
		<dc:creator>Yaniv Aknin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[atomic increment]]></category>
		<category><![CDATA[atomicity]]></category>
		<category><![CDATA[counters]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[patch]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[restful]]></category>

		<guid isPermaLink="false">http://tech.blog.aknin.name/?p=1265</guid>
		<description><![CDATA[So today I ran into the question of incrementing a counter in a RESTful manner, and wasn&#8217;t sure how to go about doing it. Googling around a bit didn&#8217;t find me a satisfactory answer, though I did find @idangazit asked the same question on Stack Overflow, but alas the question was answered by what I [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1265&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>So today I ran into the question of incrementing a counter in a RESTful manner, and wasn&#8217;t sure how to go about doing it. Googling around a bit didn&#8217;t find me a satisfactory answer, though I did find <code>@idangazit</code> asked the same <a href="http://stackoverflow.com/questions/1426845/incrementing-resource-counter-in-a-restful-way-put-vs-post">question</a> on Stack Overflow, but alas the question was answered by what I humbly felt was an inadequate answer.</p>
<p>Idan had &#8220;PUT vs. POST&#8221; in his question, but quoting the answer I just added to that question (<code>#selfplagiarism</code>!), I believe PATCH is the answer as <a href="http://tools.ietf.org/html/rfc2068#section-19.6.1">RFC 2068</a> says very well:</p>
<blockquote><p>The PATCH method is similar to PUT except that the entity contains a list of differences between the original version of the resource identified by the Request-URI and the desired content of the resource after the PATCH action has been applied. The list of differences is in a format defined by the media type of the entity (e.g., &#8220;application/diff&#8221;) and MUST include sufficient information to allow the server to recreate the changes necessary to convert the original version of the resource to the desired version.
</p></blockquote>
<p>So, for example, to update profile 123&#8242;s view count, I would do (using <a href="http://docs.python-requests.org/en/latest/index.html">requests</a>, what else?):<br />
<pre class="brush: python; light: true;">
import requests

requests.patch(
    'http://localhost:8000/profiles/123',
    'views + 1\n',
    headers={&quot;Content-Type&quot;: &quot;application/x-counters&quot;}
)
</pre></p>
<p>Which would emit something like:<br />
<pre class="brush: plain; light: true;">
PATCH /profiles/123 HTTP/1.1
Host: localhost:8000
Content-Length: 10
Content-Type: application/x-counters
Accept-Encoding: identity, deflate, compress, gzip
Accept: */*
User-Agent: python-requests/0.10.0

views + 1
</pre></p>
<p>Where the <code>x-counters</code> media type (which I just made up) is made of multiple lines of <code>field operator scalar</code> tuples. <code>views + 1</code>, <code>views = 500</code>, <code>views - 1</code> or <code>views + 3</code> are all valid syntactically (but some may be forbidden semantically). I can understand some frowning-upon making up yet another media type, but I think this approach matches the intention of the RFC quite well, it&#8217;s extremely simple and if the backend is implemented correctly, it&#8217;s atomically correct.</p>
<p>Suggestions for another approach?</p>
<p><span class="footer">p.s.: escaping spaces in field names are left as an exercise to the reader, I suggest <code>application/x-www-form-urlencoded</code> or simply using sane field names, ffs.</span></p>
<br /> Tagged: <a href='http://tech.blog.aknin.name/tag/atomic-increment/'>atomic increment</a>, <a href='http://tech.blog.aknin.name/tag/atomicity/'>atomicity</a>, <a href='http://tech.blog.aknin.name/tag/counters/'>counters</a>, <a href='http://tech.blog.aknin.name/tag/http/'>http</a>, <a href='http://tech.blog.aknin.name/tag/patch/'>patch</a>, <a href='http://tech.blog.aknin.name/tag/rest/'>rest</a>, <a href='http://tech.blog.aknin.name/tag/restful/'>restful</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/niltowrite.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/niltowrite.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/niltowrite.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/niltowrite.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/niltowrite.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/niltowrite.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/niltowrite.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/niltowrite.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/niltowrite.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/niltowrite.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/niltowrite.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/niltowrite.wordpress.com/1265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/niltowrite.wordpress.com/1265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/niltowrite.wordpress.com/1265/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1265&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tech.blog.aknin.name/2012/02/08/restfully-atomically-incrementing-a-counter-using-http-patch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/9e42ce18ec8a40b6334a6b0283d72528?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">yanivaknin</media:title>
		</media:content>
	</item>
		<item>
		<title>I wish someone wrote django-static-upstream&#8230; maybe even&#8230; me!</title>
		<link>http://tech.blog.aknin.name/2011/12/28/i-wish-someone-wrote-django-static-upstream-maybe-even-me/</link>
		<comments>http://tech.blog.aknin.name/2011/12/28/i-wish-someone-wrote-django-static-upstream-maybe-even-me/#comments</comments>
		<pubDate>Wed, 28 Dec 2011 16:29:34 +0000</pubDate>
		<dc:creator>Yaniv Aknin</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[Ideas]]></category>
		<category><![CDATA[My Projects]]></category>
		<category><![CDATA[cloudfront]]></category>
		<category><![CDATA[django-staticfiles]]></category>
		<category><![CDATA[heroku]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[s3]]></category>
		<category><![CDATA[static assets]]></category>
		<category><![CDATA[static files]]></category>
		<category><![CDATA[statics]]></category>

		<guid isPermaLink="false">http://tech.blog.aknin.name/?p=1210</guid>
		<description><![CDATA[I used to think serving static files (aka static assets) is really easy: configure nginx to serve a directory and you&#8217;re done. But things quickly became more complicated as issues like asset compilation, CDNs/scalability, file-specific custom headers, deployment complexity and development/production parity rear their ugly heads. Judging by the huge number of different asset management [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1210&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I used to think serving static files (aka static assets) is really easy: configure nginx to serve a directory and you&#8217;re done. But things quickly became more complicated as issues like asset compilation, CDNs/scalability, file-specific custom headers, deployment complexity and development/production parity rear their ugly heads. Judging by the huge <a href="http://djangopackages.com/grids/g/asset-managers/">number</a> of different asset management packages on djangopackages, it seems like I&#8217;m not the only one who ran into this problem and felt not-entirely-satisfied with all the other solutions out there. Things actually took a turn for the worse ever since I started drinking the Heroku cool-aid, and for the live of me I just can&#8217;t make sense of their best-practice with regard to serving static files. The heroku-django <a href="http://devcenter.heroku.com/articles/django">quickstart</a> conveniently sidesteps the issue of statics, and while there are a <a href="http://devcenter.heroku.com/articles/using-sass">few</a> <a href="http://devcenter.heroku.com/articles/static-sites-on-heroku">support</a> <a href="http://devcenter.heroku.com/articles/large-static-assets">articles</a> that lightly touch on neighboring subjects, nothing I found was spot-on and hands-on (this is an exception to the rule; the Heroku cool-aid is otherwise very tasty and easy to drink, to my taste so far). Ugh, why can&#8217;t there be a silver bullet to solve all this? Let me tell you about my &#8220;wishlist&#8221; for the best static serving method evar.</p>
<p>First, I want to be able to take any checkout from my VCS, maybe run an easy bootstrap function, and get a working development environment with statics served. In production, I want to serve my statics from a CDN with aggressive caching, so I need some versioning system, but I&#8217;d like to minimize deployment complexity and I want fine-grained cache invalidation of my statics. I want my statics to be served the same way (same headers, same versioning mechanism) in development and production without having to update two different locations (i.e., my S3 syncing script and my development nginx configuration). I also don&#8217;t want to have to &#8220;garbage-collect&#8221; my old statics from S3 every so and so days. Like I said, I&#8217;d like some of my statics to be served with some bells and whistles, like various custom headers (<tt>Access-Control-Allow-Origin</tt>, anyone?) or gzip compression. Speaking of bells and whistles, how about a whole marching band, since I want to serve statics that require compilation (minify/concatenate/compile scss+coffe/spritalize/etc), but I don&#8217;t want to have to rerun a &#8216;build process&#8217; every time I touch a coffee script file in development. Finally, and this isn&#8217;t something I&#8217;m not very adamant about, but I prefer my statics to be served from a different subdomain (<tt>static</tt>, not <tt>www</tt>), I think it&#8217;s cleaner, I don&#8217;t need my clients&#8217; cookies with every static request and it allows for some tricks (like using a CDN with support for a custom origin).</p>
<p>And nothing I found does all that, definitely not easily. In my dream, there&#8217;s a package called <tt>django-static-upstream</tt>, which is designed to provide a holistic approach to all these issues. I&#8217;m thinking:</p>
<ul>
<li>a pure Python/django static HTTP server (probably just <tt>django.views.static</tt> with support for the bells and whistles as mentioned above), and yeah, I think I should bloody use this server as a backend to serve my in production</li>
<li>a &#8220;vhost&#8221; middleware that will replace <tt>request.urlconf</tt> based on the Host: <tt>header</tt>; if the host starts with some prefix (say, <tt>static</tt>), the request will be served by the webserver above</li>
<li>a couple of template tags like <tt>{% static "images/logo.png" %}</tt> that will create content-hashed links to the static webserver (i.e., <tt>//static.example.com/829dd67168a3/images/logo.png</tt>); the static server will know to ignore the content-hash bit</li>
<li>this isn&#8217;t really up to the package, but it should be built to support easily setting a custom-origin supporting CDN (like CloudFront) as the origin URL; this is both to serve the statics from nearby edges CDN but also (maybe more importantly) to serve as a caching reverse proxy so the dynamic server will be fairly idle</li>
<li>support for compiling some static types on the fly (coffeescript, scss, etc) and returning the rendered result; the result may have to be cached using django&#8217;s cache (keyd by a content hash), but this is more to speed up multi-browser development where there is no CDN to serve as a reverse caching proxy than because I worry about production</li>
</ul>
<p>So now I&#8217;m thinking maybe I should write something like this. There are two reasons I&#8217;m blogging about a package before I even wrote it; first, since I wanted to flesh out in my mind what is it that I want from it. But second, and more importantly, because I&#8217;d like to tread carefully (1) before I have the hubris to start yet <strong>another</strong> assets related django package, (2) before I start serving static content with a dynamic language (what am I, mad?) and (3) because compiling static assets on runtime in violation of <a href="http://www.12factor.net/build-release-run">the fifth factor</a> in <a href="https://twitter.com/#!/hirodusk">Adam Wiggins&#8217;</a> twelve-factor app manifesto (what, you didn&#8217;t read it yet? what&#8217;s wrong with you?). These are quite a few warning signs to cross, and I&#8217;d like to get some feedback before I go there. But I honestly think I&#8217;ll be happier if I had a package to do all this, I don&#8217;t think writing it should be so hard and I hope you&#8217;d be happy using it, too.</p>
<p>The ball&#8217;s in your court, comment away.</p>
<br /> Tagged: <a href='http://tech.blog.aknin.name/tag/cloudfront/'>cloudfront</a>, <a href='http://tech.blog.aknin.name/tag/django/'>django</a>, <a href='http://tech.blog.aknin.name/tag/django-staticfiles/'>django-staticfiles</a>, <a href='http://tech.blog.aknin.name/tag/heroku/'>heroku</a>, <a href='http://tech.blog.aknin.name/tag/python/'>python</a>, <a href='http://tech.blog.aknin.name/tag/s3/'>s3</a>, <a href='http://tech.blog.aknin.name/tag/static-assets/'>static assets</a>, <a href='http://tech.blog.aknin.name/tag/static-files/'>static files</a>, <a href='http://tech.blog.aknin.name/tag/statics/'>statics</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/niltowrite.wordpress.com/1210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/niltowrite.wordpress.com/1210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/niltowrite.wordpress.com/1210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/niltowrite.wordpress.com/1210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/niltowrite.wordpress.com/1210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/niltowrite.wordpress.com/1210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/niltowrite.wordpress.com/1210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/niltowrite.wordpress.com/1210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/niltowrite.wordpress.com/1210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/niltowrite.wordpress.com/1210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/niltowrite.wordpress.com/1210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/niltowrite.wordpress.com/1210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/niltowrite.wordpress.com/1210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/niltowrite.wordpress.com/1210/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1210&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tech.blog.aknin.name/2011/12/28/i-wish-someone-wrote-django-static-upstream-maybe-even-me/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/9e42ce18ec8a40b6334a6b0283d72528?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">yanivaknin</media:title>
		</media:content>
	</item>
		<item>
		<title>Walking Python objects recursively</title>
		<link>http://tech.blog.aknin.name/2011/12/11/walking-python-objects-recursively/</link>
		<comments>http://tech.blog.aknin.name/2011/12/11/walking-python-objects-recursively/#comments</comments>
		<pubDate>Sun, 11 Dec 2011 13:16:13 +0000</pubDate>
		<dc:creator>Yaniv Aknin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[objwalk]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[recursion]]></category>
		<category><![CDATA[recursive]]></category>
		<category><![CDATA[traverse]]></category>
		<category><![CDATA[walk]]></category>

		<guid isPermaLink="false">http://niltowrite.wordpress.com/?p=1187</guid>
		<description><![CDATA[Here&#8217;s a small function that walks over any* Python object and yields the objects contained within (if any) along with the path to reach them. I wrote it and am using it to validate a deserialized datastructure, but you can probably use it for many things. In fact, I&#8217;m rather surprised I didn&#8217;t find something [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1187&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a small function that walks over any<sup>*</sup> Python object and yields the objects contained within (if any) along with the path to reach them. I wrote it and am using it to validate a deserialized datastructure, but you can probably use it for many things. In fact, I&#8217;m rather surprised I didn&#8217;t find something like this on the web already, and perhaps it should go in <tt>itertools</tt>.</p>
<p><strong>Edit:</strong> Since the original post I added infinite recursion protection following Eli and Greg&#8217;s good advice, added Python 3 compatibility and did some refactoring (which means I had to add proper unit test). You will always be able to get the latest version <a href="http://code.activestate.com/recipes/577982-recursively-walk-python-objects/">here</a>, on ActiveState&#8217;s Python Cookbook (at least until it makes its way into stdlib, fingers crossed&#8230;).</p>
<p><pre class="brush: python;">
from collections import Mapping, Set, Sequence

# dual python 2/3 compatability, inspired by the &quot;six&quot; library
string_types = (str, unicode) if str is bytes else (str, bytes)
iteritems = lambda mapping: getattr(mapping, 'iteritems', mapping.items)()

def objwalk(obj, path=(), memo=None):
    if memo is None:
        memo = set()
    iterator = None
    if isinstance(obj, Mapping):
        iterator = iteritems
    elif isinstance(obj, (Sequence, Set)) and not isinstance(obj, string_types):
        iterator = enumerate
    if iterator: 
        if id(obj) not in memo:
            memo.add(id(obj))
            for path_component, value in iterator(obj):
                for result in objwalk(value, path + (path_component,), memo):
                    yield result
            memo.remove(id(obj))
    else:       
        yield path, obj
</pre></p>
<p>And here&#8217;s a little bit of sample usage:<br />
<pre class="brush: python; light: true;">
&gt;&gt;&gt; tuple(objwalk(True))
(((), True),)
&gt;&gt;&gt; tuple(objwalk({}))
()
&gt;&gt;&gt; tuple(objwalk([1,2,3]))
(((0,), 1), ((1,), 2), ((2,), 3))
&gt;&gt;&gt; tuple(objwalk({&quot;http&quot;: {&quot;port&quot;: 80, &quot;interface&quot;: &quot;0.0.0.0&quot;}}))
((('http', 'interface'), '0.0.0.0'), (('http', 'port'), 80))
&gt;&gt;&gt; 
</pre></p>
<p><span class="footer"><em>&quot;any&quot;</em> is a strong word and Python is flexible language; I wrote this function to work with container objects that respect the <a href="http://docs.python.org/library/collections.html#collections-abstract-base-classes" title="Abstract Base Classes in the collections module"><em>ABCs</em></a> in the <tt>collections</tt> module, which mostly cover the usual builtin types and their subclasses. If there&#8217;s something significant I missed, I&#8217;d be happy to hear about it.</span></p>
<br /> Tagged: <a href='http://tech.blog.aknin.name/tag/objwalk/'>objwalk</a>, <a href='http://tech.blog.aknin.name/tag/python/'>python</a>, <a href='http://tech.blog.aknin.name/tag/recursion/'>recursion</a>, <a href='http://tech.blog.aknin.name/tag/recursive/'>recursive</a>, <a href='http://tech.blog.aknin.name/tag/traverse/'>traverse</a>, <a href='http://tech.blog.aknin.name/tag/walk/'>walk</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/niltowrite.wordpress.com/1187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/niltowrite.wordpress.com/1187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/niltowrite.wordpress.com/1187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/niltowrite.wordpress.com/1187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/niltowrite.wordpress.com/1187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/niltowrite.wordpress.com/1187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/niltowrite.wordpress.com/1187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/niltowrite.wordpress.com/1187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/niltowrite.wordpress.com/1187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/niltowrite.wordpress.com/1187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/niltowrite.wordpress.com/1187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/niltowrite.wordpress.com/1187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/niltowrite.wordpress.com/1187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/niltowrite.wordpress.com/1187/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1187&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tech.blog.aknin.name/2011/12/11/walking-python-objects-recursively/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/9e42ce18ec8a40b6334a6b0283d72528?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">yanivaknin</media:title>
		</media:content>
	</item>
		<item>
		<title>enqueue: CLI utility to queue command execution</title>
		<link>http://tech.blog.aknin.name/2011/11/19/enqueue-cli-utility-to-queue-command-execution/</link>
		<comments>http://tech.blog.aknin.name/2011/11/19/enqueue-cli-utility-to-queue-command-execution/#comments</comments>
		<pubDate>Sat, 19 Nov 2011 00:02:30 +0000</pubDate>
		<dc:creator>Yaniv Aknin</dc:creator>
				<category><![CDATA[My Projects]]></category>
		<category><![CDATA[cli]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[queueing]]></category>

		<guid isPermaLink="false">http://tech.blog.aknin.name/?p=1165</guid>
		<description><![CDATA[Update: As you can see in the comments below, and as I feared, it turned out that Lluís Batlle i Rossell already implemented something much like Enqueue, only better in many regards. I doubt I&#8217;ll keep maintaining enqueue, there&#8217;s no reason to. Oh well, it was a nice afternoon project. Something that always bugged me [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1165&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><span style="color:#990000;"><strong>Update:</strong> As you can see in the comments below, and as I feared, it turned out that <em>Lluís Batlle i Rossell</em> already <a href="http://vicerveza.homeunix.net/~viric/soft/ts/">implemented</a> something much like Enqueue, only better in many regards. I doubt I&#8217;ll keep maintaining enqueue, there&#8217;s no reason to. Oh well, it was a nice afternoon project.</span></p>
<p>Something that always bugged me with my shell workflow is the problem of queueing commands to run one after the other, while adding commands to the queue as they previous commands are being executed.</p>
<p>Take, for example, a simple usecase: we want to move three large files from <tt>diskA</tt> to <tt>diskB</tt>. The problem is that you don&#8217;t know the name of the files in advance, perhaps because you&#8217;re renaming them manually and it takes you time to type, or because you&#8217;re hunting for them in the directory tree, or whatever. Here are some solutions to this:</p>
<ul>
<li>Start one command in the background, then do something like <tt>fg ; <em>second-command</em></tt>. Then prepare the third command, but only run it after you saw the second finished. Meh. Or,</li>
<li>Just let the jobs run concurrently in the background as you run them (using the <tt>&amp;</tt> control operator). But since each command is maxing out a resource (CPU, disk, etc), this becomes woefully inefficient really quickly. Or,</li>
<li>Use a mad concoction of <tt>Ctrl-Z</tt>, <tt>fg</tt>/<tt>bg</tt>, <tt>wait n</tt> or (if you left the shell and want to add something to the queue) use a madder concoction of <tt>while pgrep -f 'mv /disk/A/foo' &gt; /dev/null; do ...</tt> (I&#8217;ll leave it as an exercise to the frustrated reader to finish that little one liner). But then again, you could also spend that time getting a paper-cut at the edge of your nostril, and it would probably be just as much fun and maybe even less error prone. Or,</li>
<li>Start a shell process reading from a named pipe (<tt>mkfifo(1)</tt>), and write the commands to the named pipe (credit to my friend and colleague <em>m0she</em> for this sneaky idea). In practice, I found it unwieldy at best, and impossible to extend with bells-and-whistle features if you need them, first and foremost, easily listing the queue and your position in it.</li>
</ul>
<p>I reckon you could think of a few more ways, but I doubt (and hope! :) none would be more convenient than to simply use <strong><a href="https://github.com/yaniv-aknin/Enqueue">Enqueue</a></strong>, a simple and hopefully lightweight Python/twisted command line queuer (written today by yours truly). Usage looks a bit like so:<br />
<pre class="brush: plain; light: true;">
$ alias nq=enqueue
$ nq add mv /disk1/file1 /disk2/file1
$ nq add mv /disk1/file2 /disk2/file2
$ nq add beep
$ nq list
* mv /disk1/file1 /disk2/file1
  mv /disk1/file2 /disk2/file2
  beep
$
</pre><br />
Nice and easy. Enqueue is still a bit rough around the edges and not very feature rich, but it does the job for me and I hope you&#8217;d like it too. Queues are managed by a twisted daemon that talks to the CLI client over UNIX domain sockets, and the whole thing fits in about 300 lines of Python. Feel free to open issues/send pull requests on GitHub if you find bugs or want to suggest something, I&#8217;ll try to keep up. Promise.</p>
<hr /></hr>
<p><span class="footer">p.s.: Why is it that every time I dabble in Python packaging I end up (a) horribly frustrated and (b) feeling the <a href="http://pypi.python.org/pypi/Enqueue/0.1.0">result</a> is awfully inadequate? Yes, I know I could probably package enqueue better, I know packaging isn&#8217;t Python&#8217;s strongest side and I know <a href="http://lmgtfy.com/?q=tarek+ziade+packaging">the future</a> is better than the present, but the present sucks and I just had to say this. Yeah, I also walk around in the summertime sayin&#8217; &#8220;how about this heat&#8221;.</span></p>
<br /> Tagged: <a href='http://tech.blog.aknin.name/tag/cli/'>cli</a>, <a href='http://tech.blog.aknin.name/tag/python/'>python</a>, <a href='http://tech.blog.aknin.name/tag/queueing/'>queueing</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/niltowrite.wordpress.com/1165/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/niltowrite.wordpress.com/1165/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/niltowrite.wordpress.com/1165/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/niltowrite.wordpress.com/1165/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/niltowrite.wordpress.com/1165/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/niltowrite.wordpress.com/1165/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/niltowrite.wordpress.com/1165/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/niltowrite.wordpress.com/1165/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/niltowrite.wordpress.com/1165/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/niltowrite.wordpress.com/1165/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/niltowrite.wordpress.com/1165/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/niltowrite.wordpress.com/1165/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/niltowrite.wordpress.com/1165/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/niltowrite.wordpress.com/1165/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1165&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tech.blog.aknin.name/2011/11/19/enqueue-cli-utility-to-queue-command-execution/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/9e42ce18ec8a40b6334a6b0283d72528?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">yanivaknin</media:title>
		</media:content>
	</item>
		<item>
		<title>pv: the pipe swiss army knife</title>
		<link>http://tech.blog.aknin.name/2011/11/05/pv-the-pipe-swiss-army-knife/</link>
		<comments>http://tech.blog.aknin.name/2011/11/05/pv-the-pipe-swiss-army-knife/#comments</comments>
		<pubDate>Sat, 05 Nov 2011 19:27:16 +0000</pubDate>
		<dc:creator>Yaniv Aknin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[command line]]></category>
		<category><![CDATA[pv]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://tech.blog.aknin.name/?p=1104</guid>
		<description><![CDATA[When using UNIX, every now and then you run into a relatively unknown command line application which, once you master it, becomes part of your &#8220;first class&#8221; commands along with cut or tr. You wince every time you work on a computer that doesn&#8217;t have it (and promptly wget-configure-make-install it) and you&#8217;re amazed your colleagues [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1104&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>When using UNIX, every now and then you run into a relatively unknown command line application which, once you master it, becomes part of your &#8220;first class&#8221; commands along with <tt>cut</tt> or <tt>tr</tt>. You wince every time you work on a computer that doesn&#8217;t have it (and promptly <tt>wget-configure-make-install</tt> it) and you&#8217;re amazed your colleagues never heard of it. I often feel <tt>pv</tt> is such a command for me. Really, this command, much like <tt>netcat</tt>, should have been written in Berkley sometime circa 1985 and be in every <tt>/usr/bin</tt> today. Alas, somehow Hobbit only wrote <tt>netcat</tt> in 1996, and it took a long while for for it to reach <tt>/usr/bin</tt> ubiquity. Similarly, Andrew Wood only <a href="http://www.ivarch.com/programs/pv.shtml?old#news">wrote</a> <tt>pv</tt> in 2002, and I hope this post will convince you to place it in all your <tt>/usr/local/bin</tt>s today and convince distribution makers to promote it to the status of a standard package as soon as possible.</p>
<p>The basic premise of <tt>pv</tt> is simple &#8211; it&#8217;s a program that copies stdin to stdout, while richly displaying progress using terminal graphics on stderr. If you use UNIX a lot and you never heard of <tt>pv</tt> before, I&#8217;m pretty sure the lightbulb is already lit above your head (if not, maybe <tt>pv</tt> isn&#8217;t for you after all or maybe it would help if you&#8217;d take a look <a href="http://www.catonmat.net/blog/unix-utilities-pipe-viewer/">this</a> review of <tt>pv</tt> to help you see why it&#8217;s so great). <tt>pv</tt> has evolved rather nicely over the years, it&#8217;s available from Ubuntu <tt>universe</tt> for a while now (why only <tt>universe</tt>? why??), and it has a slew of useful features, like rate limiting, ETA prediction for an expected amount of data, on-the-fly parameter change (increase/decrease rate limit without breaking the pipe!), multiple invocation support (measure speed in two different points of the pipe!) and so on.</p>
<p>If you&#8217;re using <tt>pv</tt>, I hope you may want to see some of the recipes I use it in; if you don&#8217;t, maybe they&#8217;ll whet your appetite (I&#8217;m using long options for <tt>pv</tt> and short options for everything else):</p>
<ol>
<li><u>The basics: copy <tt>/tmp/src/</tt> to <tt>/tmp/dst/</tt>, with progress</u></li>
<p><pre class="brush: bash; light: true;">
$ src=/tmp/src ; tar -cC &quot;$src&quot; . |
  pv --size $(du -hsk &quot;$src&quot; | cut -f1)k |
  tar -xC /tmp/dst
 142MB 0:00:02 [43.4MB/s] [======&gt;    ] 58% ETA 0:00:01
$
</pre><br />
By the way, this works great if you add <tt>nc</tt> and compression, <tt>pv</tt> can even help you decide what level of compression to use to achieve the best throughput before the CPU becomes the bottleneck.</p>
<li><u>Scale a bunch of images to a specific size, using multiple cores and with progress</u></li>
<p><pre class="brush: bash; light: true;">
$ cd /tmp/src ; ls *.jpg |
  xargs -P 4 -I % -t convert -resize 1024 % /tmp/dst/% 2&gt;&amp;1 |
  pv --line-mode --size $(ls *.jpg | wc -l) &gt; /dev/null
  96 0:00:16 [7.85/s] [===&gt;       ] 36% ETA 0:00:28
$
</pre></p>
<li><u>Get a quick assessment of the traffic rate going through some interface</u></li>
<p><pre class="brush: bash; light: true;">
$ sudo tcpdump -c 10000 -i eth1 -w - 2&gt;/dev/null | pv &gt; /dev/null
35.4MB 0:00:07 [4.56MB/s] [ &lt;=&gt;          ]
$
</pre>
</ol>
<p>Nifty, eh? I find myself inserting <tt>pv</tt> in any pipe I expect to exist for more than a few moments. How do you use <tt>pv</tt>?</p>
<br /> Tagged: <a href='http://tech.blog.aknin.name/tag/command-line/'>command line</a>, <a href='http://tech.blog.aknin.name/tag/pv/'>pv</a>, <a href='http://tech.blog.aknin.name/tag/unix/'>unix</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/niltowrite.wordpress.com/1104/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/niltowrite.wordpress.com/1104/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/niltowrite.wordpress.com/1104/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/niltowrite.wordpress.com/1104/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/niltowrite.wordpress.com/1104/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/niltowrite.wordpress.com/1104/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/niltowrite.wordpress.com/1104/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/niltowrite.wordpress.com/1104/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/niltowrite.wordpress.com/1104/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/niltowrite.wordpress.com/1104/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/niltowrite.wordpress.com/1104/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/niltowrite.wordpress.com/1104/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/niltowrite.wordpress.com/1104/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/niltowrite.wordpress.com/1104/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1104&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tech.blog.aknin.name/2011/11/05/pv-the-pipe-swiss-army-knife/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/9e42ce18ec8a40b6334a6b0283d72528?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">yanivaknin</media:title>
		</media:content>
	</item>
		<item>
		<title>nginx+gzip module might silently corrupt data upon backend failure</title>
		<link>http://tech.blog.aknin.name/2011/11/04/nginxgzip-module-might-silently-corrupt-data-upon-backend-failure/</link>
		<comments>http://tech.blog.aknin.name/2011/11/04/nginxgzip-module-might-silently-corrupt-data-upon-backend-failure/#comments</comments>
		<pubDate>Fri, 04 Nov 2011 09:33:20 +0000</pubDate>
		<dc:creator>Yaniv Aknin</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://tech.blog.aknin.name/?p=1131</guid>
		<description><![CDATA[There are several elements that make absolutely certain the page you&#8217;re reading in your browser right now is actually an accurate representation of the resource the HTTP server holds in the URL you requested1. Disregarding caching for a minute, we have two elements making sure the representation you get is protected from errors. The first [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1131&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>There are several elements that make absolutely certain the page you&#8217;re reading in your browser right now is actually an accurate representation of the resource the HTTP server holds in the URL you requested<sup>1</sup>. Disregarding caching for a minute, we have two elements making sure the representation you get is protected from errors. The first protecting element is, of course, TCP, making sure that if the server wrote two-hundred bytes in a particular order, either they&#8217;ll all arrive to your end, in order and without errors, or your TCP stack will realize something bad happen and give your user-agent (your browser) a chance to cope with the error. The need for the second protecting element is a bit more sneaky: TCP will guarantee everything the server <em>wrote</em> will arrive, i.e., bytes for which the server called <tt>write(2)</tt> or equivalent will arrive, or you&#8217;ll know something went wrong. But what about bytes the server <em>should</em> have written but didn&#8217;t write all &#8211; for example, because some component on the server&#8217;s side failed?</p>
<p>The <a href="http://www.w3.org/Protocols/HTTP/AsImplemented.html">original</a> HTTP (HTTP 0.9, 1996 time) didn&#8217;t cope with this situation at all. The signal to the client that the server finished talking was to disconnect the TCP session, which, from the client&#8217;s side, is a vague signal. Did the TCP server disconnect because it finished or because it ran into trouble (software fault, sysadmin action, kernel behaviour due to memory pressure or even a bug, etc)? Thankfully, current HTTP kicks in to complement TCP, allowing the server to do one of several things in order to make sure you&#8217;ll at least know you didn&#8217;t receive the whole picture. By far the two most common thing the server will do are to specify a <tt>Content-Length</tt> in the response&#8217;s header or to use a <tt>Transfer-Encoding</tt>, most probably <tt>chunked</tt> transfer encoding.</p>
<p>Content length is simple to grasp. The server wishes to say 200 bytes. It explicitly says: &#8220;I will say 200 bytes&#8221; in the response header. If the user-agent didn&#8217;t receive 200 bytes of response, it knows something went wrong. Chunked transfer encoding is only slightly more complex &#8211; the server will send the response in chunks, each chunks prefixed by the length of the chunk. The end of the document is marked by a zero-length chunk. So if the user-agent saw a chunk cut in the middle, or didn&#8217;t receive a zero-length chunk, it also knows something went wrong and has a chance to decide what to do about it. For example, when faced with incorrect content length, Chrome displays an <tt>ERR_CONNECTION_CLOSED</tt> error, whereas Firefox would display the portion of the page it did receive. Different behaviour, yes, but at least both user-agents in this example had a chance realize the response they received is partial. Which is really, really important, you know why? I&#8217;ll tell you why.</p>
<p>Enter caching. HTTP caching is a non-trivial matter with many unexpected gotchas and pitfalls, and I can&#8217;t cover it all here (why the complexity? I think it&#8217;s because <em>all caching</em> is an intentional form of <a href="http://en.wikipedia.org/wiki/Don%27t_Repeat_Yourself">data/state repetition</a>, and repetition is something that in my experience humans often have difficulty reasoning about). By far the best document I know about HTTP caching is <a href="http://www.mnot.net/cache_docs/">this</a> splendid guide, but if you&#8217;re in a hurry or impatient, let me summarize the points interesting for this particular post. First, caches might exist in many places, some of them might be surprising, some of them might be slightly broken or at least very aggressive (ISP transparent caches, mutter mutter cough cough). Second, among many other things, HTTP caching lets a server give a client a token together resource, telling the client &#8220;next time you request this resource, tell me you have this token; maybe I&#8217;ll just tell you that the representation you got with this token is still fresh, without transferring it all over again&#8221;. This is called an <tt>ETag</tt>, and the response that says &#8220;just use what you have in your cache&#8221; is called HTTP <tt>304 NOT MODIFIED</tt>.</p>
<p>How is this relevant to HTTP responses cut in the middle? Well, if servers didn&#8217;t have a way of telling the user-agent how long is the document, and if the response was cut in the middle due to a server fault as described above, the user-agent/sneaky-caching-proxy might cache incorrect responses. If the server also sends an <tt>ETag</tt> along with the response, the caching entity will store this <tt>ETag</tt> along with the invalid cached representation, and even when it&#8217;s time to check the representation&#8217;s freshness with the origin server, the server will just take a look at the <tt>ETag</tt>, say &#8220;yep, this is fine&#8221;, tell the cache to keep using the bad representation and &lt;sinister&gt;never ever let it recover&lt;/sinister&gt;. If this happens on a large ISP&#8217;s transparent cache, easily tens of thousand of your users could be affected. If the affected resource is a common element in many of your pages with strict syntax checking, like a javascript resource, you&#8217;re kinda screwed. The only hope in such a condition is that the client, for some reason, will specify <tt>Cache-Control: no-cache</tt> in the request, and that caching entities along the path to the server will honour this request. Browsers like caching, so they won&#8217;t usually request <tt>no-cache</tt>, although AFAIK, recently Chrome started sending <tt>no-cache</tt> when the user explicitly requests a force-reload (Cmd-R on a Mac). Other browsers don&#8217;t fare as well, and I think that hoping one of your Chrome users will force reload the bad resource in time to save the day is hardly a sturdy solution.</p>
<p>Bottom line is, it&#8217;s really important to know when a representation of a resource is broken. Which is why I was quite amazed to learn that my HTTP server of choice, nginx, doesn&#8217;t validate the <tt>Content-Length</tt> it receives from its upstreams and is simply unaware when the response it received from an upstream server is chopped off. If your response specifies a content length but closes the connection without delivering enough bytes, nginx will simply stall the request for a long time without closing the connection downstream, even though it has no hope of receiving additional data to push downstream. I tried this both with <tt>proxy_pass</tt> and <tt>uwsgi_pass</tt>, but I&#8217;m quite confident it&#8217;s true for other backends (<tt>fastcgi_pass</tt>, <tt>scgi_pass</tt>, etc). This is bad, but not as bad as the case where you want an nginx module to manipulate your content, removing existing content length/transfer encoding and applying its own (the <a href="http://wiki.nginx.org/HttpGzipModule#gzip_http_version">gzip</a> module indeed does that). If a backend error occurs while content-length-oblivious-nginx is altering the data, the content altering module will apply what it applies to the bytes it received, <em>add new content-length/transfer-encoding, assuring everyone the response is OK</em>, and entice user-agents or even proxies to enter the almost-never-recover bad cache scenario I described in the previews paragraph. Ouch!</p>
<p>The proper way to fix this, IMHO, is that nginx simply must start looking at the upstream&#8217;s content length (or transfer encoding, once nginx starts using chunked responses with its upstreams). Part of the reason I&#8217;m writing this post is that Maxim Dounin, venerable nginx comitter and an OK chap overall, <a href="http://forum.nginx.org/read.php?2,216085,216094#msg-216094">told me</a> he doesn&#8217;t consider this a top priority at the moment, but I humbly disagree with his assessment of how serious the issue is. Until such a time as nginx is fixed about this, I think you must disable all content-manipulating nginx modules and instead handle all message length affecting work in your upstream (compression, addition, etc). This is what I opted to do with my django based web app, I replaced nginx&#8217;s gzip module with Django&#8217;s <tt><a href="https://docs.djangoproject.com/en/dev/ref/middleware/#module-django.middleware.gzip">GZipMiddleware</a></tt>. It&#8217;s a terrible shame though. It&#8217;s doing the job of nginx for it, probably in a lesser fashion than how nginx could, it <a href="http://www.python.org/dev/peps/pep-0333/#handling-the-content-length-header">violates</a> a <b>must not</b> clause in Python&#8217;s WSGI PEP333, and I have empiric proof that Tim Berners-Lee chokes a kitten every time you do it.</p>
<p>But what&#8217;s the alternative? Risk invisibly cached corrupt data for an undetermined length of time? Ditch nginx, which I think is the best HTTP server on this planet despite this debacle? Nah. Both are unacceptable.</p>
<hr /></hr>
<p><span class="footer"><sup>1</sup> This post assumes convenient values of &#8220;absolutely certain&#8221;; also, everything related to security/content tampering is out of scope in this post. I&#8217;m talking about possibly misbehaving but certainly well-meaning components.</span></p>
<br /> Tagged: <a href='http://tech.blog.aknin.name/tag/django/'>django</a>, <a href='http://tech.blog.aknin.name/tag/http/'>http</a>, <a href='http://tech.blog.aknin.name/tag/nginx/'>nginx</a>, <a href='http://tech.blog.aknin.name/tag/python/'>python</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/niltowrite.wordpress.com/1131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/niltowrite.wordpress.com/1131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/niltowrite.wordpress.com/1131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/niltowrite.wordpress.com/1131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/niltowrite.wordpress.com/1131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/niltowrite.wordpress.com/1131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/niltowrite.wordpress.com/1131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/niltowrite.wordpress.com/1131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/niltowrite.wordpress.com/1131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/niltowrite.wordpress.com/1131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/niltowrite.wordpress.com/1131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/niltowrite.wordpress.com/1131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/niltowrite.wordpress.com/1131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/niltowrite.wordpress.com/1131/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1131&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tech.blog.aknin.name/2011/11/04/nginxgzip-module-might-silently-corrupt-data-upon-backend-failure/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/9e42ce18ec8a40b6334a6b0283d72528?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">yanivaknin</media:title>
		</media:content>
	</item>
		<item>
		<title>Introducing django-ajaxerrors</title>
		<link>http://tech.blog.aknin.name/2011/01/31/introducing-django-ajaxerrors/</link>
		<comments>http://tech.blog.aknin.name/2011/01/31/introducing-django-ajaxerrors/#comments</comments>
		<pubDate>Mon, 31 Jan 2011 12:02:14 +0000</pubDate>
		<dc:creator>Yaniv Aknin</dc:creator>
				<category><![CDATA[My Projects]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[ajaxerrors]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[unhandled errors]]></category>
		<category><![CDATA[unhandled exceptions]]></category>

		<guid isPermaLink="false">http://tech.blog.aknin.name/?p=1054</guid>
		<description><![CDATA[Today I finished a small django middleware that facilitates development of AJAX applications. I reckon most if not all Django developers know about Django&#8217;s useful debug-mode unhandled error page (you know, the one that looks like this). However, when an AJAX request reaches a faulty view, the error page will not be rendered in your [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1054&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Today I finished a small django middleware that facilitates development of AJAX applications. I reckon most if not all Django developers know about Django&#8217;s useful debug-mode <a href="http://docs.djangoproject.com/en/dev/topics/http/views/#the-500-server-error-view">unhandled error page</a> (you know, the one that looks like <a href="http://new-media.djangobook.com/content/en/1.0/chapter04/missing_template.png">this</a>). However, when an AJAX request reaches a faulty view, the error page will not be rendered in your browser but instead be received by your AJAX error handler (assuming you even had one), which is almost always not what you want. This forces you you to find some other way to reach your traceback information. For example, before I wrote this package, I used to regularly open Chrome&#8217;s developer tools, find the failed resource in the Resources tab, and then either read through the raw HTML (yuck) or copy and paste it to a file and double click it (tedious).</p>
<p>As <a href="http://groups.google.com/group/django-users/browse_thread/thread/820101441f4dc070">you</a> <a href="http://djangosnippets.org/snippets/650/">can</a> <a href="http://djangosnippets.org/snippets/802/">see</a>, this bothered other people, too, but I couldn&#8217;t find a decent solution on the web. Thankfully, since the problem is really about ease of development and not very relevant in environments where DEBUG is false (you&#8217;d get the traceback via email anyway), and since I do most of my development work locally (and I suspect so do many other Django developers), I figured the solution can take advantage of the server being a full fledged desktop with a modern browser and a GUI. Enter <tt>ajaxerrors.middleware.ShowAJAXErrors</tt>.</p>
<p>This little middleware intercepts all unhandled view exceptions, pickles the technical error page and uses Python&#8217;s webbrowser module to direct a new browser tab at a special URL that will serve (and delete) the previously stored page. All this is only triggered if <tt>DEBUG</tt> and <a class="code" href="http://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.is_ajax">request.is_ajax()</a> is true, so pretty much everything you&#8217;re used to in your development flow should stay the same. Sweet. <tt>ShowAJAXError</tt> can also be configured to run arbitrary user-defined handlers with the error information, and even comes with a handler for <a href="http://en.wikipedia.org/wiki/Growl_(software)" class="code">growlnotify</a> and a handler that replies to all failed AJAX calls with HTTP OK result containing an empty JSON object (I use it for development, YMMV).</p>
<p>django-ajaxerrors is on <a href="http://pypi.python.org/pypi/django-ajaxerrors/1.0">PyPI</a>, so you can install it with <tt>pip</tt> or <tt>easy_install</tt> with ease. You can clone/fork the code (and read the more detailed readme) <a href="http://github.com/yaniv-aknin/django-ajaxerrors">here</a>. Also, if you&#8217;d like to see what django-ajaxerrors is like without any special effort, you can <a href="http://github.com/downloads/yaniv-aknin/django-ajaxerrors/ajaxerrors-demo.tar.bz2">download</a> a simple AJAX app I&#8217;ve written for the purpose of developing django-ajaxerrors itself. The app has django-ajaxerrors contained within it, so this is pretty much all you need to see django-ajaxerrors in action about 1 minute from now:<br />
<pre class="brush: bash;">
$ virtualenv -q demo
$ pip install -q -E demo django
$ cd demo
$ source bin/activate
(demo)$ curl -s -o - http://cloud.github.com/downloads/yaniv-aknin/django-ajaxerrors/ajaxerrors-demo.tar.bz2 | tar jx
(demo)$ cd ajaxerrors-demo/
(demo)$ python manage.py runserver
# demoserver running...
</pre><br />
Now point your browser at the development server, and play with the calculator a bit. Hint: the calculator is not protected against division by zero. :)</p>
<p>I hope you like django-ajaxerrors, it&#8217;s MIT licensed, so do what you will with it. Let me know if you need assistance or ran into a snag, or, even better, if you want to contribute something to it.</p>
<br /> Tagged: <a href='http://tech.blog.aknin.name/tag/ajax/'>ajax</a>, <a href='http://tech.blog.aknin.name/tag/ajaxerrors/'>ajaxerrors</a>, <a href='http://tech.blog.aknin.name/tag/django/'>django</a>, <a href='http://tech.blog.aknin.name/tag/unhandled-errors/'>unhandled errors</a>, <a href='http://tech.blog.aknin.name/tag/unhandled-exceptions/'>unhandled exceptions</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/niltowrite.wordpress.com/1054/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/niltowrite.wordpress.com/1054/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/niltowrite.wordpress.com/1054/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/niltowrite.wordpress.com/1054/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/niltowrite.wordpress.com/1054/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/niltowrite.wordpress.com/1054/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/niltowrite.wordpress.com/1054/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/niltowrite.wordpress.com/1054/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/niltowrite.wordpress.com/1054/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/niltowrite.wordpress.com/1054/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/niltowrite.wordpress.com/1054/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/niltowrite.wordpress.com/1054/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/niltowrite.wordpress.com/1054/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/niltowrite.wordpress.com/1054/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1054&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tech.blog.aknin.name/2011/01/31/introducing-django-ajaxerrors/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/9e42ce18ec8a40b6334a6b0283d72528?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">yanivaknin</media:title>
		</media:content>
	</item>
		<item>
		<title>Something&#8217;s horribly wrong with Dell (and HP)</title>
		<link>http://tech.blog.aknin.name/2010/12/09/somethings-horribly-wrong-with-dell-and-hp/</link>
		<comments>http://tech.blog.aknin.name/2010/12/09/somethings-horribly-wrong-with-dell-and-hp/#comments</comments>
		<pubDate>Thu, 09 Dec 2010 06:58:07 +0000</pubDate>
		<dc:creator>Yaniv Aknin</dc:creator>
				<category><![CDATA[Offtopic]]></category>
		<category><![CDATA[dell]]></category>
		<category><![CDATA[rant]]></category>

		<guid isPermaLink="false">http://tech.blog.aknin.name/?p=1040</guid>
		<description><![CDATA[Maybe it&#8217;s not the most interesting content I&#8217;ve ever published, but I&#8217;d like to share something with my readers, secretly hoping that maybe some Dell or HP employee would ever get to see this. My aunt, who lives in far-away London, asked me for help choosing her new computer. Her requirements from the new computer [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1040&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Maybe it&#8217;s not the most interesting content I&#8217;ve ever published, but I&#8217;d like to share something with my readers, secretly hoping that maybe some Dell or HP employee would ever get to see this. My aunt, who lives in far-away London, asked me for help choosing her new computer. Her requirements from the new computer are dead simple: it should have dual screen support (she&#8217;s a translator and prefers the original and translated text open side-by-side) and preferably the chassis should have something purple on it. That&#8217;s it. I reckon if she wasn&#8217;t in London I&#8217;d pop by one of the small computer shops on the street near my home and pick up a brandless computer to fit her needs. I reckon I could do fine with the equivalent of something around 250GBP.</p>
<p>Since she&#8217;s far away and since my mom has a surprisingly long-lived Dell OptiPlex GX260 (Pentium 4!) and since I have a friend whose been badgering me for years that bitsie computers are bullocks and that going with a brand, preferably Dell (in his opinion) is the only sensible option, I asked my aunt if she&#8217;d like to shell the extra money for a brand name and she agreed. So I went to Dell UK&#8217;s stupid website, which keeps shoving deals I don&#8217;t want in my face while not letting me understand really what is it that I&#8217;m going to buy and for what price. Admittedly, I haven&#8217;t really bought a computer I cared much about in years, but still I thought that I knew my way around computers, and for the life of me I couldn&#8217;t be certain what&#8217;s the cheapest Dell with to which you can connect two monitors, and that&#8217;s all the dude ever wanted anyway.</p>
<p>I clicked the banner which was flying on the screen (you think I&#8217;m kidding, but there was a banner and it was flying) which read &#8220;Chat with a sales representative now&#8221;. As I expected I was taken to a chat with some poor sap who seemed intent on failing the Turing test. Honestly, I think <a href="http://en.wikipedia.org/wiki/Dr._Sbaitso">Dr. Sbaitso</a> would have helped me better than this person did<sup>1</sup>. After specifying my extremely simple requirements and after receiving several links that didn&#8217;t work because the Dell website was built by faceless and nameless gnomes who obviously never heard of beautiful URLs, I literally had to force the sales rep to give me just the name of the model they recommended and Google it. Namely, turns out I was looking for an <a href="http://search.dell.co.uk/1/1/24755-piano-black-colour-dell-inspiron-560-mt-desktop.html">Dell Inspiron 560 MT</a> (model number: D005619, if the link won&#8217;t work for you guys either), priced at a whooping 500GBP. The computer was an obvious overkill for my needs, and <em>still I couldn&#8217;t find a proper specification sheet saying simply that it had dual monitor support</em>. I didn&#8217;t feel like I could trust the sales rep anyway, I felt our interests were horribly misaligned and he really couldn&#8217;t care. Every other sentence the sales rep uttered was &#8220;I hope I helped you today sir, would you like to proceed with me to checkout?&#8221; or something to that effect.</p>
<p>So I tried figuring things out myself, going backwards, first choosing the cheapest Dell with an ATI GPU (a Radeon 3000), and then searching about the Radeon 3000, and the AMD 760G chipset, and other (non-Dell) manufacturers that make boards with the 760G &#8211; all in order to find a picture of the board where I could <em>see</em> what will I be receiving, to no avail. There are many specs lying around the Internet and many boards and some had both DVI/VGA and some didn&#8217;t and I couldn&#8217;t come up with a simple, definite answer for my aunt, who&#8217;se a really kind person but would really rather not donate 500GBP to Dell needlessly. Amazingly, Dell thinks it makes sense to add a sentence like <em>NOTE: Offerings may vary by region. For more information regarding the configuration of your computer, click Start -&gt; Help and Support and select the option to view information about your computer.</em> to a spec sheet. Good thing <tt>RFC791</tt> didn&#8217;t read <em>[the Identification field is] an identifying value assigned by the sender to aid in assembling the fragments of a datagram, but it may vary by region and be something completely different, or may not. We&#8217;ll see</em>, or else the friggin&#8217; Internet probably wouldn&#8217;t have existed as we know it.</p>
<p>Visiting HP&#8217;s website yielded frighteningly similar results. I&#8217;m pretty sure I&#8217;d tell her to go Apple by now, but she&#8217;s far away and OSX is a whole new interface and I don&#8217;t have much time these days for support calls and she needs good Hebrew support (for the translations), which I&#8217;m afraid Apple lacks. Besides, Apple scares me, and that&#8217;s a reason for another post but not now. So I&#8217;m stuck. Ya hear that, fatso Dell and HP boneheaded executives? I&#8217;m stuck! There&#8217;s a guy here who literally grew up with computers and probably bought more than a hundred of them over the years, he wants to give you money to finance your unjustified bonuses, and he&#8217;s unable to, because you couldn&#8217;t keep your product lines reasonably small, your model names and submodel number sensible (and sub-sub-model number, and sub-sub-sub-model number, repeat at stupidum), your specifications sheets straight, your website functional and your sales representatives earning more than the equivalent of 10 pennies an hour! What the heck is wrong with you guys? How hard do you think it is to sell <em>me</em> a computer?</p>
<p>Screw this dude, let&#8217;s go bowling. But what will I tell my aunt?!</p>
<hr /></hr>
<p><span class="footer"><sup>1</sup> &lt;evil&gt;Suddenly I&#8217;m thinking that was I tasked with covert development of software that would pass the Turing test, I&#8217;d probably either train it against these &#8216;sales reps&#8217; or try to get it a job as such a sales rep. Hmm.&lt;/evil&gt;</span></p>
<br /> Tagged: <a href='http://tech.blog.aknin.name/tag/dell/'>dell</a>, <a href='http://tech.blog.aknin.name/tag/rant/'>rant</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/niltowrite.wordpress.com/1040/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/niltowrite.wordpress.com/1040/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/niltowrite.wordpress.com/1040/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/niltowrite.wordpress.com/1040/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/niltowrite.wordpress.com/1040/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/niltowrite.wordpress.com/1040/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/niltowrite.wordpress.com/1040/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/niltowrite.wordpress.com/1040/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/niltowrite.wordpress.com/1040/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/niltowrite.wordpress.com/1040/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/niltowrite.wordpress.com/1040/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/niltowrite.wordpress.com/1040/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/niltowrite.wordpress.com/1040/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/niltowrite.wordpress.com/1040/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1040&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tech.blog.aknin.name/2010/12/09/somethings-horribly-wrong-with-dell-and-hp/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/9e42ce18ec8a40b6334a6b0283d72528?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">yanivaknin</media:title>
		</media:content>
	</item>
		<item>
		<title>zsh and virtualenv</title>
		<link>http://tech.blog.aknin.name/2010/10/14/zsh-and-virtualenv/</link>
		<comments>http://tech.blog.aknin.name/2010/10/14/zsh-and-virtualenv/#comments</comments>
		<pubDate>Wed, 13 Oct 2010 23:53:04 +0000</pubDate>
		<dc:creator>Yaniv Aknin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[prompt]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[virtualenv]]></category>
		<category><![CDATA[zsh]]></category>

		<guid isPermaLink="false">http://tech.blog.aknin.name/?p=1023</guid>
		<description><![CDATA[A week ago or so I finally got off my arse and did the pragmatic programmer thing, setting aside those measly ten minutes to check out virtualenv (well, I also checked out buildout, but I won&#8217;t discuss it in this post). I knew pretty much what to expect, but I wanted to get my hands [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1023&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>A week ago or so I finally got off my arse and did the pragmatic programmer thing, setting aside those measly ten minutes to check out <strong>virtualenv</strong> (well, I also checked out <em>buildout</em>, but I won&#8217;t discuss it in this post). I knew pretty much what to expect, but I wanted to get my hands dirty with them so I could see what I assumed I&#8217;ve been missing out on for so long (and indeed I promptly kicked myself for not doing it sooner, yada yada, you probably know the drill about well-known-must-know-techniques-and-tools-that-somehow-you-don&#8217;t-know). Much as I liked virtualenv, there were two things I didn&#8217;t like about environment activation in virtualenv. First, I found typing &#8216;source bin/activate&#8217; (or similar) cumbersome, I wanted something short and snazzy that worked regardless of <em>where</em> inside the virtualenv I am so long as I&#8217;m somewhere in it (it makes sense to me to say that I&#8217;m &#8216;in&#8217; a virtualenv when my current working directory is somewhere under the virtualenv&#8217;s directory). Note that being &#8220;in&#8221; a virtualenv isn&#8217;t the same as activating it; you can change directory from virtualenv foo to virtualenv bar, and virtualenv foo will remain active. Indeed, this was the second problem I had: I kept forgetting to activate my virtualenv as I started using it or to deactivate the old one as I switched from one to another. </p>
<p>zsh to the rescue. You may recall that I already <a href="http://tech.blog.aknin.name/2010/05/14/switching-to-mercurial-taming-zsh/">mentioned</a> the tinkering I&#8217;ve done to make it easier to remember my current DVCS branch. Briefly, I have a function called <tt>_rprompt_dvcs</tt> which is evaluated whenever zsh displays my prompt and if I&#8217;m in a git/Mercurial repository it sets my right prompt to the name of the current branch in blue/green. You may also recall that while I use git itself to tell me if I&#8217;m in a git repository at all and which branch I&#8217;m at (using <tt>git branch --no-color 2&gt; /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'</tt>), I had to resort to a small C program (<a href="http://bitbucket.org/yaniv_aknin/fast_hg_root" class="code">fast_hg_root</a>) in order to decide whether I&#8217;m in a Mercurial repository or not and then I manually parse the branch with <tt>cat</tt>. As I said in the previous post about hg and prompt, I&#8217;m not into giving hg grief about speed vs. git, but when it comes to the <em>prompt</em> things are different.</p>
<p>With this background in mind, I was perfectly armed to solve my woes with virtualenv. First, I changed <tt>fast_hg_root</tt> to be slightly more generic and search for a user-specified &#8220;magic&#8221; filename upwards from the current working directory (I called the outcome <a href="https://bitbucket.org/yaniv_aknin/walkup" class="code">walkup</a>, it&#8217;s really simple and nothing to write home about&#8230;). For example, to mimic <tt>fast_hg_root</tt> with <tt>walkup</tt>, you&#8217;d run it like so: <kbd>$ walkup .hg</kbd>. Using <kbd>$ walkup bin/activate</kbd> to find my current virtualenv (if any at all), I could easily add the following function to my zsh environment:<br />
<pre class="brush: bash;">
act () {
        if [ -n &quot;$1&quot; ]
        then
                if [ ! -d &quot;$1&quot; ]
                then
                        echo &quot;act: $1 no such directory&quot;
                        return 1
                fi
                if [ ! -e &quot;$1/bin/activate&quot; ]
                then
                        echo &quot;act: $1 is not a virtualenv&quot;
                        return 1
                fi
                if which deactivate &gt; /dev/null
                then
                        deactivate
                fi
                cd &quot;$1&quot;
                source bin/activate
        else
                virtualenv=&quot;$(walkup bin/activate)&quot; 
                if [ $? -eq 1 ]
                then
                        echo &quot;act: not in a virtualenv&quot;
                        return 1
                fi
                source &quot;$virtualenv&quot;/bin/activate
        fi
}
</pre><br />
Now I can type <kbd>$ act</kbd> anywhere I want in a virtualenv, and that virtualenv will become active; this saves figuring out the path to <tt>bin/activate</tt> and ending up typing something ugly like <kbd>$ source ../../bin/activate</kbd>. If you want something that can work for you without a special binary on your host, there&#8217;s also a pure-shell version of the same function in the collapsed snippet below.<br />
<pre class="brush: bash; collapse: true; light: false; toolbar: true;">
function act() {
    if [ -n &quot;$1&quot; ]; then
        if [ ! -d &quot;$1&quot; ]; then
            echo &quot;act: $1 no such directory&quot;
            return 1
        fi
        if [ ! -e &quot;$1/bin/activate&quot; ]; then
            echo &quot;act: $1 is not a virtualenv&quot;
            return 1
        fi

        if which deactivate &gt; /dev/null; then
            deactivate
        fi
        cd &quot;$1&quot;
        source bin/activate
    else
        stored_dir=&quot;$(pwd)&quot;
        while [ ! -f bin/activate ]; do
            if [ $(pwd) = / ]; then
                echo &quot;act: not in a virtualenv&quot;
                cd &quot;$stored_dir&quot;
                return 1
            fi
            cd ..
        done
        source bin/activate
        cd &quot;$stored_dir&quot;
    fi
}
</pre></p>
<p>This was nice, but only solved half the problem: I still kept forgetting to activate the virtualenv, or moving out of a virtualenv and forgetting that I left it activated (this can cause lots of confusion, for example, if you&#8217;re simultaneously trying out <a href="http://code.google.com/p/django-facebookconnect/">this</a>, <a href="http://github.com/sciyoshi/pyfacebook/">this</a>, <a href="http://github.com/uswaretech/Django-Socialauth">this</a> or <a href="http://github.com/flashingpumpkin/django-socialregistration">that</a> django-facebook integration modules, more than one of them thinks that <tt>facebook</tt> is a good idea for a namespace to take!). To remind me, I wanted my left prompt to reflect my virtualenv in the following manner (much like my right prompt reflects my current git/hg branch if any):</p>
<ol>
<li>If I&#8217;m not in a virtualenv and no virtualenv is active, do nothing.</li>
<li>If I&#8217;m in a virtualenv and it is not active, display its name as part of the prompt in white.</li>
<li>If I&#8217;m in a virtualenv and it is active, display its name as part of the prompt in green.</li>
<li>If I&#8217;m not in a virtualenv but some virtualenv is active, display its name in yellow.</li>
<li>Finally, if I&#8217;m in one virtualenv but another virtualenv is active, display both their names in red.</li>
</ol>
<p>So, using <tt>walkup</tt>, I wrote the virtualenv parsing functions:<br />
<pre class="brush: bash;">
function active_virtualenv() {
    if [ -z &quot;$VIRTUAL_ENV&quot; ]; then
        # not in a virtualenv
        return
    fi

    basename &quot;$VIRTUAL_ENV&quot;
}

function enclosing_virtualenv() {
    if ! which walkup &gt; /dev/null; then
        return
    fi
    virtualenv=&quot;$(walkup bin/activate)&quot;
    if [ -z &quot;$virtualenv&quot; ]; then
        # not in a virtualenv
        return
    fi

    basename $(grep VIRTUAL_ENV= &quot;$virtualenv&quot;/bin/activate | sed -E 's/VIRTUAL_ENV=&quot;(.*)&quot;$/\1/')
}
</pre></p>
<p>All that remained was to change my lprompt function to look like so (remember I have <tt>setopt prompt_subst</tt> on):<br />
<pre class="brush: bash;">
function _lprompt_env {
    local active=&quot;$(active_virtualenv)&quot;
    local enclosing=&quot;$(enclosing_virtualenv)&quot;
    if [ -z &quot;$active&quot; -a -z &quot;$enclosing&quot; ]; then
        # no active virtual env, no enclosing virtualenv, just leave
        return
    fi
    if [ -z &quot;$active&quot; ]; then
        local color=white
        local text=&quot;$enclosing&quot;
    else
        if [ -z &quot;$enclosing&quot; ]; then
            local color=yellow
            local text=&quot;$active&quot;
        elif [ &quot;$enclosing&quot; = &quot;$active&quot; ]; then
            local color=green
            local text=&quot;$active&quot;
        else
            local color=red
            local text=&quot;$active&quot;:&quot;$enclosing&quot;
        fi
    fi
    local result=&quot;%{$fg[$color]%}${text}$rst &quot;
    echo -n $result
}

function lprompt {
    local col1 col2 ch1 ch2
    col1=&quot;%{%b$fg[$2]%}&quot;
    col2=&quot;%{$4$fg[$3]%}&quot;
    ch1=$col1${1[1]}
    ch2=$col1${1[2]}

    local _env='$(_lprompt_env)'

    local col_b col_s
    col_b=&quot;%{$fg[green]%}&quot;
    col_s=&quot;%{$fg[red]%}&quot;

    PROMPT=&quot;\
$bgc$ch1\
$_env\
%{$fg_bold[white]%}%m:\
$bgc$col2%B%1~%b\
$ch2$rst \
$col2%#$rst &quot;
}
</pre></p>
<p>A bit lengthy, but not very difficult. I suffered a bit until I figured out that I should escape the result of <tt>_lprompt_virtualenv</tt> using a percent sign (like so: <tt>"%{$fg[$color]%}${text}$rst "</tt>), or else the ANSII color escapes are counted for cursor positioning purposes and screw up the prompt&#8217;s alignment. Meh. Also, remember to set <tt>VIRTUAL_ENV_DISABLE_PROMPT=True</tt> somewhere, so virtualenv&#8217;s simple/default prompt manipulation functionality won&#8217;t kick in and screw things up for you, and we&#8217;re good to go.</p>
<p>The result looks like so (I still don&#8217;t know how to do a terminal-&#8221;screenshot&#8221;-to-html, here&#8217;s a crummy png):<br />
<a href="http://niltowrite.files.wordpress.com/2010/10/zsh-and-virtualenv.png"><img src="http://niltowrite.files.wordpress.com/2010/10/zsh-and-virtualenv.png?w=440&#038;h=266" alt="" title="zsh-and-virtualenv" width="440" height="266" class="aligncenter size-full wp-image-1035" /></a></p>
<p>Voila! Feel free to use these snippets, and happy zshelling!</p>
<br /> Tagged: <a href='http://tech.blog.aknin.name/tag/prompt/'>prompt</a>, <a href='http://tech.blog.aknin.name/tag/python/'>python</a>, <a href='http://tech.blog.aknin.name/tag/virtualenv/'>virtualenv</a>, <a href='http://tech.blog.aknin.name/tag/zsh/'>zsh</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/niltowrite.wordpress.com/1023/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/niltowrite.wordpress.com/1023/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/niltowrite.wordpress.com/1023/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/niltowrite.wordpress.com/1023/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/niltowrite.wordpress.com/1023/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/niltowrite.wordpress.com/1023/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/niltowrite.wordpress.com/1023/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/niltowrite.wordpress.com/1023/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/niltowrite.wordpress.com/1023/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/niltowrite.wordpress.com/1023/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/niltowrite.wordpress.com/1023/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/niltowrite.wordpress.com/1023/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/niltowrite.wordpress.com/1023/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/niltowrite.wordpress.com/1023/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1023&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tech.blog.aknin.name/2010/10/14/zsh-and-virtualenv/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/9e42ce18ec8a40b6334a6b0283d72528?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">yanivaknin</media:title>
		</media:content>

		<media:content url="http://niltowrite.files.wordpress.com/2010/10/zsh-and-virtualenv.png" medium="image">
			<media:title type="html">zsh-and-virtualenv</media:title>
		</media:content>
	</item>
		<item>
		<title>Eulogy to a server</title>
		<link>http://tech.blog.aknin.name/2010/10/01/eulogy-to-a-server/</link>
		<comments>http://tech.blog.aknin.name/2010/10/01/eulogy-to-a-server/#comments</comments>
		<pubDate>Fri, 01 Oct 2010 11:54:45 +0000</pubDate>
		<dc:creator>Yaniv Aknin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[crash]]></category>
		<category><![CDATA[disk]]></category>
		<category><![CDATA[ouch]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[storage]]></category>
		<category><![CDATA[temperature]]></category>

		<guid isPermaLink="false">http://tech.blog.aknin.name/?p=1010</guid>
		<description><![CDATA[You don&#8217;t know it, but I&#8217;ve started writing this blog several times before it actually went live, and every time I scraped whatever post I started with (the initial run was on blogger.com). I just didn&#8217;t think these posts were all too interesting, they were about my monstrous home server, donny. Maybe this is still [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1010&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>You don&#8217;t know it, but I&#8217;ve started writing this blog several times before it actually went live, and every time I scraped whatever post I started with (the initial run was on blogger.com). I just didn&#8217;t think these posts were all too interesting, they were about my monstrous home server, <tt>donny</tt>. Maybe this is still not interesting, but I&#8217;m metaphorically on the verge of tears and I just have to tell someone of what happened, to repent me of my horrible sin. You may not read if you don&#8217;t want to. I bought donny about 2.5-3 years ago, to replace my aging home storage server (I had about 3x250GB at the time, no RAID). There&#8217;s not much to say about donny&#8217;s hardware (Core 2 Duo, 2GB of RAM, Asus P5K-WS motherboard), other than the gargantuan <a href="http://www.google.com/search?sourceid=chrome&amp;ie=UTF-8&amp;q=stacker+810">CoolerMaster Stacker 810</a> chassis with room for 14 (!) SATA disks. Initially I bought 8&#215;0.5TB SATA Hitachi disks for it, and added more as I had the chance. I guess I bought it because at the time I&#8217;d hang around disks all day long, I must&#8217;ve felt the need to compensate for something (my <a href="http://www.xivstorage.com/">job</a> at the time was mostly around software, but still, you can&#8217;t ignore the shipping crates of SATA disks in lab).</p>
<p>Anyway, most of its life donny ran OpenSolaris. One of our customers had a big ZFS deployment, I&#8217;ve always liked Solaris most of all the big Unices (I never thought it really better than Linux, it just Sucked Less&trade; than the other big iron Unices), I totally drank the cool-aid about &#8220;ZFS: the last word in File System&#8221; (notice how the first Google hit for <a href="http://www.google.com/search?aq=0&amp;oq=last+word+in+f&amp;sourceid=chrome&amp;ie=UTF-8&amp;q=zfs+the+last+word+in+file+systems">this</a> search term is &#8220;Bad Request&#8221; :) and dtrace <em>really</em> blew me away. So I chose OpenSolaris. Some of those started-but-never-finished posts were about whether I was happy with OpenSolaris and ZFS or not, I never found them interesting enough to even finish them. So even if I don&#8217;t wanna discuss that particularly, it should be noted that if we look at how I voted with my feet, I ended up migrating donny to Ubuntu 10.04.1/mdadm RAID5/ext4 when my wife and I got back from our long trip abroad.</p>
<p>Migration was a breeze, the actual migration process convinced me I&#8217;ve made the right choice in this case. Over the time with ZFS (both at work and at home) I realized it&#8217;s probably good but certainly not magical and not the end of human suffering with regard to storage. In exchange for giving up zfs and dtrace I received the joys of Ubuntu, most notably a working package management system and sensible defaults to make life so much easier, along with the most vibrant eco-system there is. I bought donny 4&#215;2.0TB SATA WD Cavier Green disks, made a rolling upgrade for the data while relying on zfs-fuse (it went well, despite a small and old <a href="http://groups.google.com/group/zfs-fuse/browse_thread/thread/75a3c5395cddda9f/8a8aa261397be393?lnk=gst&amp;q=data+corruption#8a8aa261397be393">bug</a>) and overall the downtime was less than an hour for the installation of the disks. At the time of the disaster, donny held one RAID5 array made of 4x2TB, one RAID5 array made of 4x.5TB, one soon-to-be-made RAID5 array made of 3x1TB+1&#215;1.5TB (I bought a larger drive after one of the 1TB failed a while ago), and its two boot disks. I was happy. donny, my wife and me, one happy family. Until last night.</p>
<p>I was always eyeing donny&#8217;s small boot disks (what a waste of room&#8230; and with all these useless SATA disks I&#8217;ve accumulated over the years and have lying about&#8230;), so last night I wanted to break the 2x80GB mirror and roll-upgrade to a 2x1TB boot configuration, planning on using the extra space for&#8230; well, I&#8217;ll be honest, I don&#8217;t know for what. I&#8217;ll admit it &#8211; I got a bit addicted to seeing the TB suffix near the free space column of <tt>df -h</tt> at home (at work you can see better suffixes :). I just have hardware lying around, and I love never deleting ANYTHING, and I love keeping all the .isos of everything ever (Hmm&#8230; RHEL3 for Itanium&#8230; that <em>must</em> come in handy <em>some</em> day&#8230;) and keeping an image of every friend and relative&#8217;s Windows computer I ever fixed (it&#8217;s amazing how much time this saves), and never keeping any media I buy in plastic&#8230; and, well, the fetish of just having a big server. Heck, it sure beats farmville.</p>
<p>So, indeed, last night I broke that mirror, and installed that 1TB drive, and this morning I started re-mirroring the boot, and while I was at it I started seeing some of the directory structure was wrong so I redistributed stuff inside the RAIDs, and all the disks where whirring merrily at the corner of the room, and I was getting cold so I turned off the AC, and suddenly donny starts beeping (I didn&#8217;t even remember I installed that pcspkr script for mdadm) and I get a flurry of emails regarding disks failures in the md devices. WTF? Quickly I realized that donny was practically boiling hot (SMART read one of the disks at 70 degrees celsius), at which point I did an emergency shutdown and realized&#8230; that last night I disconnected the power cable running from the PSU to <em>several</em> fans, forgot to reconnect it, and now I&#8217;ve effectively cooked my server. Damn.</p>
<p>I&#8217;m not sure what to do now. I still have some friends who know stuff about harddisks (like, know the stuff you have to sign NDAs with the disk manufacturers in order to know), and I&#8217;m trying to pick my network about what to do next. Basically, from what I hear so far, I should keep donny off, let the disks cool down, be ready with lots of room on a separate host to copy stuff out of it, boot it up in a cool room, take the most critical stuff out and then do whatever, it doesn&#8217;t matter, cuz the disks are dead even if they seem alive. I&#8217;m told never to trust any of the disks that were inside during the malfunction (that&#8217;s &gt;$1,000USD worth of disks&#8230;), once a disk reached 70 degrees, even far less, don&#8217;t get near it, even if it&#8217;s new. Admittedly, these guys are used to handling enterprise disk faults, where $1,000USD in hardware costs (and even many many times that amount) is nothing compared to data loss, but this is the gist of what I&#8217;m hearing so far. If you have other observations, let me know. It&#8217;s frustratingly difficult to get reliable data about disk failures on the Internet; I know just what to do in case of logical corruption of any sort; but I don&#8217;t know <em>precisely</em> what to do in a case like this, and in case of a controller failure, and a head crash, and so on, and so forth. I know it&#8217;s a lot about luck, but what&#8217;s the best way to give donny the highest chance of survival?</p>
<p>On a parting note, I&#8217;ll add that I&#8217;m a very sceptic kind of guy, but when it comes to these things I&#8217;m rather mystical. It all stems from my roots as a System Administrator; what else can comfort a lonely 19-year-old sysadmin trying to salvage something from nothing in a cold server room at 03:27AM on a Saturday? So now I blame all of this for the name I gave donny. I named it so because I name all my hosts at home after characters from <a href="http://www.imdb.com/title/tt0118715/">Big Lebowski</a> (I&#8217;m typing this on Dude, my laptop), and I called the server donny. The email address I gave it (so it could send me those FzA#$%! S.M.A.R.T reports it never did!) was named <a href="http://www.imdb.com/character/ch0003517/">Theodore Donald Kerabatsos</a>. The backup server, which is tiny compared to donny and doesn&#8217;t hold nearly as much stuff as I&#8217;d like to have back now, is called Francis Donnelly. The storage pools (and then RAID volumes) were called <em>folgers</em>, <em>receptacle</em>, <em>modest</em> and <em>cookies</em> (if you don&#8217;t understand, you should have paid more attention to Donny&#8217;s funeral in The Big Lebowski). And, indeed, as I predicted without knowing it, it ended up being friggin&#8217; cremated. May Stallman bless its soul.</p>
<p>I guess I&#8217;m a moron for not thinking about this exact scenario; I was kinda assuming smartmontools and would be SMART (ha!) enough to shutdown when the disks reach 50 degrees, and maybe there is such a setting and I just didn&#8217;t enable it&#8230; I guess by now it doesn&#8217;t matter. I&#8217;m one sad hacker. I can&#8217;t believe I did this to myself.</p>
<br /> Tagged: <a href='http://tech.blog.aknin.name/tag/crash/'>crash</a>, <a href='http://tech.blog.aknin.name/tag/disk/'>disk</a>, <a href='http://tech.blog.aknin.name/tag/ouch/'>ouch</a>, <a href='http://tech.blog.aknin.name/tag/server/'>server</a>, <a href='http://tech.blog.aknin.name/tag/storage/'>storage</a>, <a href='http://tech.blog.aknin.name/tag/temperature/'>temperature</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/niltowrite.wordpress.com/1010/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/niltowrite.wordpress.com/1010/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/niltowrite.wordpress.com/1010/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/niltowrite.wordpress.com/1010/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/niltowrite.wordpress.com/1010/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/niltowrite.wordpress.com/1010/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/niltowrite.wordpress.com/1010/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/niltowrite.wordpress.com/1010/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/niltowrite.wordpress.com/1010/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/niltowrite.wordpress.com/1010/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/niltowrite.wordpress.com/1010/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/niltowrite.wordpress.com/1010/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/niltowrite.wordpress.com/1010/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/niltowrite.wordpress.com/1010/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1010&amp;subd=niltowrite&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tech.blog.aknin.name/2010/10/01/eulogy-to-a-server/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/9e42ce18ec8a40b6334a6b0283d72528?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">yanivaknin</media:title>
		</media:content>
	</item>
	</channel>
</rss>
