<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>mstplbg</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/mstplbg/" />
    <link rel="self" type="application/atom+xml" href="http://blogs.perl.org/users/mstplbg/atom.xml" />
    <id>tag:blogs.perl.org,2009-11-03:/users/mstplbg//646</id>
    <updated>2011-03-27T10:45:46Z</updated>
    <subtitle>A blog about the Perl programming language</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 4.38</generator>

<entry>
    <title>Long-running requests with Progress Bar in Dancer / AnyEvent</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/mstplbg/2011/03/long-running-requests-with-progress-bar-in-dancer-anyevent.html" />
    <id>tag:blogs.perl.org,2011:/users/mstplbg//646.1594</id>

    <published>2011-03-27T10:23:23Z</published>
    <updated>2011-03-27T10:45:46Z</updated>

    <summary> For an application of mine which does very long-running requests (the server needs to communicate with a slow backend over the internet), I wanted to show the user a progress bar. Also, it should not just display some progress,...</summary>
    <author>
        <name>mstplbg</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/mstplbg/">
        <![CDATA[<p>
For an application of mine which does very long-running requests (the server needs to communicate with a slow backend over the internet), I wanted to show the user a progress bar. Also, it should not just display <strong>some</strong> progress, but the real deal (communicate with the server to find out the current progress), because the browser already just displays some progress.
</p>

<p>
So, to outline my idea: When the user sends a request to the route, let’s call it /long, Dancer would immediately return a page with a little javascript that periodically calls /progress and updates the progress bar. When /progress returns undef, the operation is done and the user gets redirected to the /success route handler.
</p>

<p>
Since Dancer is not asynchronous by nature, this requires using AnyEvent (see my previous posts). You have to be aware of how AnyEvent works: Just calling a timer which does the long-running operation once will not be sufficient, as the timer execution blocks and Dancer won't handle requests while AnyEvent is in control. Instead, you should cut it into little blocks. In my case, this is easy, since I’m doing HTTP requests and AnyEvent::HTTP handles them just fine.
</p>

<p>
Alright, let’s dive into the code. I will start with the Dancer part:
</p>

<pre>
package poc;
use Dancer ':syntax';
use AnyEvent;

<p>our $VERSION = '0.1';</p>

<p>set serializer => 'JSON';<br />
        <br />
my %long_ops;<br />
</pre><br />
<p><br />
We have just included AnyEvent, set the default serializer to JSON (very convenient in the javascript later) and defined a %long_ops hash.<br />
</p></p>

<pre>        
get '/long' => sub {
    session 'progress' => 0;
    session 'progresslimit' => 5;
    $long_ops{foo} = {
        cnt => 0,
        guard => AnyEvent->timer(after => 1, interval => 1, cb => sub {
            my $cnt = $long_ops{foo}->{cnt} + 1;
            $long_ops{foo}->{cnt} = $cnt;
            if ($cnt == 5) {
                undef $long_ops{foo}->{guard};
                session 'progress' => undef;
            } else {
                session 'progress' => $cnt;
                debug "progress is $cnt";
            }
        }
    };
    template 'index';
};
</pre>

<p>
The /long route is where all the magic happens. First we set the 'progress' and 'progresslimit' session variables to 0 and 5, meaning that progress starts at 0 and can reach 5 at max. Afterwards, we initialize our data structure (note that due to this being a proof-of-concept we just use 'foo' instead of a reasonable per-client identifier) with the current status (cnt) and a guard for the AnyEvent timer. As I explained in previous posts, AnyEvent objects fall out of scope if you don’t keep a reference to them.
</p>

<p>
The timer will be triggered 5 times and all it does is increasing the progress on every iteration. As soon as it reaches 5, it will undef the guard and thereby disable itself.
</p>

<p>
The route returns the template 'index' at which we will take a look in a second.
</p>

<pre>
get '/progress' => sub {
    {
        progress => session('progress'),
        progresslimit => session('progresslimit')
    }
};
</pre>

<p>
The /progress route returns a hash with the current and maximum progress. Due to the default serializer being set to JSON, Dancer will automatically serialize the hash to JSON.
</p>

<p>
Now that we have the server side, you can already test it with curl:
</p>

<pre>
$ curl --cookie-jar /tmp/cookies http://localhost:8000/long
$ while [ 1 ] ; do curl -b /tmp/cookies http://localhost:8000/progress; sleep 1; done
</pre>

<p>
Now we just need to do the same in javascript. Of course, we will make use of the bundled jQuery that comes with Dancer, so besides modifying views/index.tt, no other changes are required.
</p>

<pre>
&lt;h1&gt;Long-running request demo&lt;/h1&gt;

<p>&lt;div id="progress"&gt;Progress not yet initialized&lt;/div&gt;</p>

<p>&lt;script type="text/javascript"&gt;<br />
function pollProgress() {<br />
    $.getJSON('/progress', function(data) {<br />
        if (data.progress === null) {<br />
            return;<br />
        }<br />
        $('#progress').text('progress: ' + data.progress + ' / ' + data.progresslimit);<br />
        setTimeout(pollProgress, 1000);<br />
    });<br />
}   <br />
    <br />
$(document).ready(function() {<br />
    pollProgress();<br />
});         <br />
&lt;/script&gt;<br />
</pre></p>

<p>
Since this is not a jQuery tutorial, I will cover only briefly what I’m doing here: When the document is loaded, pollProgress() will be called to get the initial progress (current = 0, max = 5). This is done by calling jQuery’s getJSON helper with an appropriate callback function. The callback exits if progress is null (undef in Perl) or otherwise updates the div with id progress and schedules the next call of pollProgress() in one second.
</p>

<p>
That’s it for now. I think I’m going to make a Dancer::Plugin out of this so that you can use it easily. Comments/Improvements very welcome!
</p>]]>
        
    </content>
</entry>

<entry>
    <title>AnyEvent and Dancer: CondVars</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/mstplbg/2010/12/anyevent-and-dancer-condvars.html" />
    <id>tag:blogs.perl.org,2010:/users/mstplbg//646.1251</id>

    <published>2010-12-16T08:45:41Z</published>
    <updated>2010-12-16T08:55:01Z</updated>

    <summary> In my last post, I explained how to get an AnyEvent-&gt;timer to work in a Dancer application. There’s nothing wrong with timers, but if you are using AnyEvent, you usually have to deal with CondVars. There are two things...</summary>
    <author>
        <name>mstplbg</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/mstplbg/">
        <![CDATA[<p>
In my last post, I explained how to get an AnyEvent->timer to work in a Dancer application.
</p>

<p>
There’s nothing wrong with timers, but if you are using AnyEvent, you usually have to deal with CondVars. There are two things you can do with a CondVar: Either you register a callback which will be called when the CondVar is triggered, or you call recv and it will block until the CondVar is triggered. In a route of your Dancer application, you probably want to block until you got all the data you want to display to your user.
</p>

<p>
Take the following (made-up) example which uses a CondVar:
</p>

<pre>
get '/' => sub {
    my $cv = AnyEvent->condvar;
    my $timer = AnyEvent->timer(after => 1, cb => sub { $cv->send(1) });
    my $result = $cv->recv;
    template 'foo', { result => $result };
};
</pre>

<p>
You will get a runtime error stating "AnyEvent::CondVar: recursive blocking wait detected". This is because Twiggy also uses a CondVar as exit_guard, to run infinitely long (blocking on a CondVar is an easy way to run the main loop).
</p>

<p>
The solution is to use a specific eventloop, such as EV, and call EV->loop instead of blocking on a CondVar:
</p>

<pre>
#!/usr/bin/env perl
use strict;
use warnings;
use EV;
use Twiggy::Server;
use Dancer;
use npmd;

<p>my $server = Twiggy::Server->new(<br />
    host => '0.0.0.0',<br />
    port => 5000<br />
);</p>

<p>my $app = sub {<br />
    my $env = shift;<br />
    my $request = Dancer::Request->new( $env );<br />
    Dancer->dance( $request );<br />
};</p>

<p>$server->register_service($app);</p>

<p>EV->loop<br />
</pre></p>]]>
        
    </content>
</entry>

<entry>
    <title>Using AnyEvent and Dancer</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/mstplbg/2010/12/using-anyevent-and-dancer.html" />
    <id>tag:blogs.perl.org,2010:/users/mstplbg//646.1244</id>

    <published>2010-12-15T10:49:22Z</published>
    <updated>2010-12-15T11:08:10Z</updated>

    <summary> In our Hackerspace RaumZeitLabor in Mannheim, Germany, we have a &quot;Network Power Manager 2000&quot; which is a device that has 8 power sockets and is able to turn these sockets on/off when told so via network. We use it...</summary>
    <author>
        <name>mstplbg</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/mstplbg/">
        <![CDATA[<p>
In our Hackerspace <a href="http://www.raumzeitlabor.de/">RaumZeitLabor</a> in Mannheim, Germany, we have a "Network Power Manager 2000" which is a device that has 8 power sockets and is able to turn these sockets on/off when told so via network. We use it to save some power when nobody is at our space.
</p>

<p>
That sounds quite nice, but we had to reverse-engineer the protocol. Afterwards, we noticed that only one (!) connection to that device is possible. So our first approach of using a little script to communicate with it was not optimal: It had timing problems because the NPM2000 took a little bit longer to close the TCP connection.
</p>

<p>
Therefore, I decided to write a little webapp using the excellent <a href="http://www.perldancer.org/">Dancer framework</a> which talks to the NPM2000 and provides a nice API to the user(s). It also should keep one TCP connection open all the time to save the overhead of creating a new connection and waiting for old connections to close properly on both sides.
</p>

<p>
For creating and using said TCP connection I decided to use AnyEvent::Socket. The main issue with this approach is that Dancer doesn’t use the AnyEvent mainloop and thus  AnyEvent won’t work at all.
</p>

<p>
The nice people in #dancer suggested taking a look at Twiggy, an AnyEvent HTTP server for PSGI. It can be easily combined with Dancer and uses AnyEvent. So, to run a Dancer application with Twiggy, use:
</p>

<pre>
cpanm Dancer Twiggy
dancer -a npmd
cd npmd
plackup -s Twiggy bin/app.pl
</pre>

<p>
Now that’s great, we have an AnyEvent-based server running our Dancer application. So, let’s use an AnyEvent timer in lib/npmd.pm:
</p>

<pre>
package npmd;
use Dancer ':syntax';
use AnyEvent;

<p>our $VERSION = '0.1';</p>

<p>my $w; </p>

<p>get '/' => sub {<br />
        $w = AnyEvent->timer(after => 1, interval => 1, cb => sub {<br />
                debug 'timer msg!';<br />
        });<br />
        template 'index';<br />
};</p>

<p>true;<br />
</pre></p>

<p>
After the first request to the application in your browser you should see the message 'timer msg' on your terminal every second.
</p>

<p>
Let’s instead create the timer outside a route, so that it runs all the time:
</p>

<pre>
package npmd;
use Dancer ':syntax';
use AnyEvent;

<p>our $VERSION = '0.1';</p>

<p>my $w = AnyEvent->timer(after => 1, interval => 1, cb => sub {<br />
        debug 'timer msg!';<br />
});</p>

<p>get '/' => sub {<br />
    template 'index';<br />
};</p>

<p>true;<br />
</pre></p>

<p>
Oops. That won’t work. The code is run, but $w falls out of scope immediately because we are not using it in any handler. This causes AnyEvent to delete the timer. There are two ways to fix this: use 'our $w' instead of 'my $w' or use $w in any of your routes.
</p>

<p>
So, a working version could look like this:
</p>

<pre>
package npmd;
use Dancer ':syntax';
use AnyEvent;

<p>our $VERSION = '0.1';</p>

<p>our $w;<br />
    $w = AnyEvent->timer(after => 1, interval => 1, cb => sub {<br />
        debug 'timer msg';<br />
    });</p>

<p>get '/' => sub {<br />
    template 'index';<br />
};</p>

<p>true;<br />
</pre></p>]]>
        
    </content>
</entry>

</feed>
