<?xml version="1.0" encoding="UTF-8"?>
<rss version='2.0' xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Kristian Øllegaard</title>
    <description>testing</description>
    <link>https://kristianoellegaard.silvrback.com/feed</link>
    <atom:link href="https://kristianoellegaard.silvrback.com/feed" rel="self" type="application/rss+xml"/>
    <category domain="kristianoellegaard.silvrback.com">Content Management/Blog</category>
    <language>en-us</language>
      <pubDate>Sat, 18 May 2013 12:05:00 -0500</pubDate>
    <managingEditor>kristian@oellegaard.com (Kristian Øllegaard)</managingEditor>
      <item>
        <guid>http://blog.kristian.io/new-version-of-django-hvad#311</guid>
          <pubDate>Sat, 18 May 2013 12:05:00 -0500</pubDate>
        <link>http://blog.kristian.io/new-version-of-django-hvad</link>
        <title>New version of django-hvad</title>
        <description></description>
        <content:encoded><![CDATA[<p>During the sprints at Djangocon I finally had the opportunity to work a bit on django-hvad. The package now supports Django 1.5. This release will probably be the last before a 1.0 release that will drop the &#39;nani&#39; compatibility module. The 0.3 release is mainly a stability and performance update.</p>

<p>Thanks to all the contributors.</p>

<p>Get it today from your favorite cheese shop</p>
]]></content:encoded>
      </item>
      <item>
        <guid>http://blog.kristian.io/sockjs-and-tornado-for-python-real-time-web-projects#309</guid>
          <pubDate>Mon, 08 Apr 2013 12:21:00 -0500</pubDate>
        <link>http://blog.kristian.io/sockjs-and-tornado-for-python-real-time-web-projects</link>
        <title>SockJS and Tornado for Python real-time web projects </title>
        <description></description>
        <content:encoded><![CDATA[<p>At Djangocon EU last year, <a href="http://lanyrd.com/2012/djangocon-europe/strwx/#link-kfft">I gave a talk</a> about how you could easily get up and running with real-time web applications using Django and Socket.IO. I have now been running an application using this principle for a year and I am everything but a fan of it. I decided i <em>had</em> to switch to something else.</p>

<p>My first impression of <a href="https://github.com/sockjs/sockjs-client">SockJS</a> wasn&#39;t very good. I thought the documentation was poor and the commit on the main (client) library wasn&#39;t very new. However, after reviewing other possibilites I decided that SockJS with <a href="https://github.com/MrJoes/sockjs-tornado">sockjs-tornado</a> had to be the best option at the moment.</p>

<p>I found a <a href="https://gist.github.com/mrjoes/3284402">great gist</a> that showed most of the way. From this gist you get the basic transport and just need to implement some sort of authentication. I also had to set it up for running on Heroku, which unfortunately means waiving one of the essential features of SockJS, namely Websockets (btw, heroku - please add support for this!). In this case I was not too concerned about authorization, just authentication. If your usecase is different, you might want to implement another/your own authentication.</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">tornado</span> <span class="kn">import</span> <span class="n">web</span><span class="p">,</span> <span class="n">ioloop</span>
<span class="kn">from</span> <span class="nn">sockjs.tornado</span> <span class="kn">import</span> <span class="n">SockJSRouter</span><span class="p">,</span> <span class="n">SockJSConnection</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">tornadoredis</span>
<span class="kn">import</span> <span class="nn">urlparse</span>
<span class="kn">from</span> <span class="nn">django.core</span> <span class="kn">import</span> <span class="n">signing</span>
<span class="kn">import</span> <span class="nn">logging</span>

<span class="k">class</span> <span class="nc">Connection</span><span class="p">(</span><span class="n">SockJSConnection</span><span class="p">):</span>
    <span class="n">clients</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">send_error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">error_type</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Standard format for all errors</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">({</span>
            <span class="s1">&#39;data_type&#39;</span><span class="p">:</span> <span class="s1">&#39;error&#39;</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">error_type</span> <span class="k">else</span> <span class="s1">&#39;</span><span class="si">%s</span><span class="s1">_error&#39;</span> <span class="o">%</span> <span class="n">error_type</span><span class="p">,</span>
            <span class="s1">&#39;data&#39;</span><span class="p">:</span> <span class="p">{</span>
                <span class="s1">&#39;message&#39;</span><span class="p">:</span> <span class="n">message</span>
            <span class="p">}</span>
        <span class="p">}))</span>

    <span class="k">def</span> <span class="nf">send_message</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">data_type</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Standard format for all messages</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">({</span>
            <span class="s1">&#39;data_type&#39;</span><span class="p">:</span> <span class="n">data_type</span><span class="p">,</span>
            <span class="s1">&#39;data&#39;</span><span class="p">:</span> <span class="n">message</span><span class="p">,</span>
        <span class="p">}))</span>

    <span class="k">def</span> <span class="nf">on_open</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Request the client to authenticate and add them to client pool.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">authenticated</span> <span class="o">=</span> <span class="bp">False</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">channel</span> <span class="o">=</span> <span class="bp">None</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">send_message</span><span class="p">({},</span> <span class="s1">&#39;request_auth&#39;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">clients</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">on_message</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Handle authentication and notify the client if anything is not ok,</span>
<span class="sd">        but don&#39;t give too many details</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">message</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
        <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">send_error</span><span class="p">(</span><span class="s2">&quot;Invalid JSON&quot;</span><span class="p">)</span>
            <span class="k">return</span>
        <span class="k">if</span> <span class="n">message</span><span class="p">[</span><span class="s1">&#39;data_type&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;auth&#39;</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">authenticated</span><span class="p">:</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">channel</span> <span class="o">=</span> <span class="n">signing</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span>
                    <span class="n">message</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;token&#39;</span><span class="p">],</span>
                    <span class="n">key</span><span class="o">=</span><span class="n">SECRET_KEY</span><span class="p">,</span>
                    <span class="n">salt</span><span class="o">=</span><span class="n">message</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;salt&#39;</span><span class="p">],</span>
                    <span class="n">max_age</span><span class="o">=</span><span class="mi">40</span>  <span class="c1"># Long time out for heroku idling processes.</span>
                    <span class="c1"># For other cases, reduce to 10</span>
                <span class="p">)</span>
            <span class="k">except</span> <span class="p">(</span><span class="n">signing</span><span class="o">.</span><span class="n">BadSignature</span><span class="p">,</span> <span class="ne">KeyError</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">send_error</span><span class="p">(</span><span class="s2">&quot;Token invalid&quot;</span><span class="p">,</span> <span class="s1">&#39;auth&#39;</span><span class="p">)</span>
                <span class="k">return</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">authenticated</span> <span class="o">=</span> <span class="bp">True</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">channel</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">send_message</span><span class="p">({</span><span class="s1">&#39;message&#39;</span><span class="p">:</span> <span class="s1">&#39;success&#39;</span><span class="p">},</span> <span class="s1">&#39;auth&#39;</span><span class="p">)</span>
            <span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Client authenticated for </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">channel</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">send_error</span><span class="p">(</span><span class="s2">&quot;Invalid data type </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">message</span><span class="p">[</span><span class="s1">&#39;data_type&#39;</span><span class="p">])</span>
            <span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Invalid data type </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">message</span><span class="p">[</span><span class="s1">&#39;data_type&#39;</span><span class="p">])</span>

    <span class="k">def</span> <span class="nf">on_close</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Remove client from pool. Unlike Socket.IO connections are not</span>
<span class="sd">        re-used on e.g. browser refresh.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">clients</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
        <span class="k">return</span> <span class="nb">super</span><span class="p">(</span><span class="n">Connection</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">on_close</span><span class="p">()</span>
</pre></div>
<p>By now, you have probably realized that we are storing clients on the class. This means we can&#39;t properly load balance this to multiple nodes without session stickyness. This sucks. I&#39;m trying to figure out a way to store clients inside redis, but for now, session stickyness is required (or if you just run it on one server, you should be fine).</p>

<p>If you watched my talk, you already know that I love redis. My original Socket.IO solution was basically just a frontend to redis. Redis has served me very well for a year, so now I&#39;ll show you how to automatically forward messages from redis to the clients. First, add this method to the above class:</p>
<div class="highlight"><pre><span></span>    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">pubsub_message</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">clients</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">client</span><span class="o">.</span><span class="n">authenticated</span> <span class="ow">and</span> <span class="n">client</span><span class="o">.</span><span class="n">channel</span> <span class="o">==</span> <span class="n">msg</span><span class="o">.</span><span class="n">channel</span><span class="p">:</span>
                <span class="n">client</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">msg</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
</pre></div>
<p>Now we just need to run the Tornado server and subscribe to redis:</p>
<div class="highlight"><pre><span></span><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="n">url</span> <span class="o">=</span> <span class="n">urlparse</span><span class="o">.</span><span class="n">urlparse</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;REDISTOGO_URL&#39;</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;OPENREDIS_URL&#39;</span><span class="p">,</span> <span class="s1">&#39;redis://localhost:6379&#39;</span><span class="p">)))</span>
    <span class="n">pool</span> <span class="o">=</span> <span class="n">tornadoredis</span><span class="o">.</span><span class="n">ConnectionPool</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="n">url</span><span class="o">.</span><span class="n">hostname</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="n">url</span><span class="o">.</span><span class="n">port</span><span class="p">)</span>
    <span class="n">c</span> <span class="o">=</span> <span class="n">tornadoredis</span><span class="o">.</span><span class="n">Client</span><span class="p">(</span><span class="n">connection_pool</span><span class="o">=</span><span class="n">pool</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="n">url</span><span class="o">.</span><span class="n">password</span><span class="p">)</span>
    <span class="n">c</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span>
    <span class="n">c</span><span class="o">.</span><span class="n">psubscribe</span><span class="p">(</span><span class="s2">&quot;*&quot;</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">msg</span><span class="p">:</span> <span class="n">c</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="n">Connection</span><span class="o">.</span><span class="n">pubsub_message</span><span class="p">))</span>

    <span class="n">Router</span> <span class="o">=</span> <span class="n">SockJSRouter</span><span class="p">(</span><span class="n">Connection</span><span class="p">,</span> <span class="s1">&#39;/namespace-here&#39;</span><span class="p">,</span> <span class="nb">dict</span><span class="p">(</span><span class="n">disabled_transports</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;websocket&#39;</span><span class="p">]))</span>  <span class="c1"># Disable websockets for heroku</span>

    <span class="n">app</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">Application</span><span class="p">(</span><span class="n">Router</span><span class="o">.</span><span class="n">urls</span><span class="p">)</span>
    <span class="n">app</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;PORT&quot;</span><span class="p">,</span> <span class="mi">8080</span><span class="p">))</span>
    <span class="n">ioloop</span><span class="o">.</span><span class="n">IOLoop</span><span class="o">.</span><span class="n">instance</span><span class="p">()</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
</pre></div>
<p>You definitely want to remove the part where I disable websockets, if you are lucky enough to be hosted somewhere where they support websockets. (Please mail me, if you know a host that offers websockets in eu-west). Furthermore you should make a prefix, so you are still able to use pubsub in redis, without it being sent to SockJS. <code>&#39;namespace-here&#39;</code> is the url your Connection class will be served at. This will enable you to namespace your different services later on.</p>

<p>Now, put it all in a file and run it!</p>

<p>Create a simple TemplateView or equivalent in your web application and insert the following JavaScript in script tags:</p>
<div class="highlight"><pre><span></span><span class="kd">function</span> <span class="nx">connect</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">auth_json</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">sock</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SockJS</span><span class="p">(</span><span class="nx">url</span><span class="p">);</span>
    <span class="nx">sock</span><span class="p">.</span><span class="nx">onopen</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
        <span class="nx">sock</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">auth_json</span><span class="p">);</span>
    <span class="p">};</span>
    <span class="nx">sock</span><span class="p">.</span><span class="nx">onmessage</span> <span class="o">=</span>  <span class="kd">function</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">data</span> <span class="o">=</span> <span class="nx">jQuery</span><span class="p">.</span><span class="nx">parseJSON</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">data_type</span> <span class="o">==</span> <span class="s1">&#39;data&#39;</span><span class="p">)</span> <span class="p">{</span>
            <span class="c1">// parse your data here</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">data_type</span> <span class="o">==</span> <span class="s1">&#39;auth_error&#39;</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">throw</span> <span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">message</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">};</span>
<span class="p">}</span>
<span class="nx">connect</span><span class="p">(</span><span class="s2">&quot;http://localhost:8080/namespace-here&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">);</span>
</pre></div>
<p>In our web application (in this case, django) we generate `` like this:</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.core</span> <span class="kn">import</span> <span class="n">signing</span>
<span class="kn">import</span> <span class="nn">json</span>

<span class="n">auth_json</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">({</span>
    <span class="s1">&#39;data_type&#39;</span><span class="p">:</span> <span class="s1">&#39;auth&#39;</span><span class="p">,</span>
    <span class="s1">&#39;data&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;salt&#39;</span><span class="p">:</span> <span class="n">SOME_SALT</span><span class="p">,</span>
        <span class="s1">&#39;token&#39;</span><span class="p">:</span> <span class="n">signing</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="s1">&#39;channel&#39;</span><span class="p">,</span><span class="n">SECRET_KEY</span><span class="p">,</span> <span class="n">salt</span><span class="o">=</span><span class="n">SOME_SALT</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">})</span>
</pre></div>
<p>And make sure to include SockJS somewhere before the above:</p>
<div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&quot;http://cdn.sockjs.org/sockjs-0.3.min.js&quot;</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</pre></div>
<p>Now you should be ready to start sending events to the browser, from python through redis. Let&#39;s try.</p>
<div class="highlight"><pre><span></span><span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">redis</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">r</span> <span class="o">=</span> <span class="n">redis</span><span class="o">.</span><span class="n">Redis</span><span class="p">()</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">r</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span><span class="s2">&quot;channel&quot;</span><span class="p">,</span> <span class="s2">&quot;hello&quot;</span><span class="p">)</span>
<span class="il">0L</span>
</pre></div>
<p>Depending whether &quot;channel&quot; matches your pattern and whether you have an open connection, this will return either 0L or 1L, afaik the number of &quot;listeners&quot; to your message. You will get front-end error though, as you are not passing in properly formatted JSON. My script assumes you send messages formatted like this:</p>
<div class="highlight"><pre><span></span><span class="p">{</span>
    <span class="nt">&quot;data_type&quot;</span><span class="p">:</span> <span class="s2">&quot;data&quot;</span><span class="p">,</span>
    <span class="nt">&quot;data&quot;</span><span class="p">:</span> <span class="p">{</span>
        <span class="nt">&quot;message&quot;</span><span class="p">:</span> <span class="s2">&quot;here&quot;</span><span class="p">,</span>
        <span class="nt">&quot;or any other&quot;</span><span class="p">:</span> <span class="s2">&quot;key/value pairs&quot;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>That was all for now. If you enjoyed this blog post, check out my <a href="https://twitter.com/oellegaard">twitter</a> for updates.</p>
]]></content:encoded>
      </item>
      <item>
        <guid>http://blog.kristian.io/new-version-of-django-health-check#308</guid>
          <pubDate>Thu, 28 Mar 2013 17:15:00 -0500</pubDate>
        <link>http://blog.kristian.io/new-version-of-django-health-check</link>
        <title>New version of django-health-check</title>
        <description></description>
        <content:encoded><![CDATA[<p>You might never have heard of <a href="http://www.github.com/KristianOellegaard/django-health-check/">django-health-check</a> before, but it is one of my open source projects. You can write small plugins (5-10 lines) that does basic checks for e.g. file system, database and cache.</p>

<p><strong>Whats new:</strong></p>

<p>I completely refactored the API for returning the status. Previously you would return a <code>HealthCheckStatusType</code> - now you either return <code>True</code> or raise one of the provided exceptions: <code>ServiceUnavailable</code> or <code>ServiceReturnedUnexpectedResult</code>.</p>

<p>With the newest release I made sure the code works with python2.7+ (yes, that <em>includes python3</em>).</p>

<p><strong>Go ahead and grab it:</strong></p>

<p><a href="http://www.github.com/KristianOellegaard/django-health-check/">Github</a></p>

<p><a href="https://pypi.python.org/pypi/django-health-check/0.2">PyPi</a></p>
]]></content:encoded>
      </item>
  </channel>
</rss>