Feeds:
Posts
Comments

Posts Tagged ‘plack’

Streaming Plack

Thanks to Douglas and Jakub for pointing me at the appropriate part of the PSGI spec for streaming.

Miyagawa mentions that plack streaming can be blocking, and running this with Starman demonstrates that nicely.

my $app = sub {
    my $env = shift;

    return sub {
        my $respond = shift;
        my $writer = $respond->([200, ['Content-Type', 'text/html']]);

        for (1..5) {
            my $dt = localtime;
            $writer->write("[ $dt ]
\n"
); sleep 2; } $writer->close(); }; };

Starman attributes include:

'psgi.streaming' => 1,
'psgi.nonblocking' => ''

Firing off two requests at the same time, the second doesn’t start until the first completes.

[ Mon May 30 18:56:16 2011 ]
[ Mon May 30 18:56:18 2011 ]
[ Mon May 30 18:56:20 2011 ]
[ Mon May 30 18:56:22 2011 ]
[ Mon May 30 18:56:24 2011 ]
[ Mon May 30 18:56:26 2011 ]
[ Mon May 30 18:56:28 2011 ]
[ Mon May 30 18:56:30 2011 ]
[ Mon May 30 18:56:32 2011 ]
[ Mon May 30 18:56:34 2011 ]

Read Full Post »

Plack Vs FastCGI

I’ve been sold on Plack for a while. This clarifies a part of the reason nicely1.

If you design a fibonacci() function, would you make it print the result to STDOUT, or return the result as a return value?

(It’s referring to the PSGI spec rather than Plack, but I figure the latter needs press a bit more)

Quick thought though – if a page takes a long time to generate, the stdout technique can deliver a bit at a time. Is there a plack plugin for that, or is the answer to go for ajax these day and deliver the page outline asap?


1. Namely that printing to stdout always seemed like a horrible and inefficient hack.

Read Full Post »

$ date
Tue Apr  6 20:40:38 BST 2010
$ perl -MPOSIX -le 'print "Week ",
>                         POSIX::strftime("%V", gmtime(time))'
Week 14

Perl Plack

First of all the plack links as that is what I am currently interested in. Note: Most of these links are not from the past few weeks, but they are the best articles that I have found so far on Plack.

I read Simon Cozens on PSGI and Plack several times. I don’t think I get it as well as him yet though.

I’m a lumberjaph has an article on using Plack::Middleware::ConditionalGET Plack::Middleware::ETag to return a 304 Not Modified response when requesting the same ETag twice. I like the idea of getting the Plack infrastructure to do as much of the work as possible – less [personal] coding is better.

My own post on getting started with Plack/Twiggy shows that requesting the handler (with e.g. install Plack::Handler::Twiggy) is the easiest way to get all of the dependencies. This works on Windows with Strawberry Perl. Digging a little deeper, there are a few windows specific issues I uncovered when looking into Plack Auto Restart but a few of these have been fixed since I posted.

Other Windows Web Posts

Windows really is the unloved ugly cousin in the perl world. Alias finds out that Dancer doesn’t work at all on Windows. Alexis Sukrieh followed up with a note that this will be worked on for the Dancer 1.2 release.

afoolishmanifesto talks about using the catalyst dev server on Windows / Strawberry Perl due to problems with building mod_perl. Interestingly one of the commenters suggests a Plack engine.

Finally, I’ve added acidcycles.wordpress.com to my reader. Not only is he talking about Catalyst and templating engines such as HTML::Zoom but he also mentioned building an Emacs site with Catalyst which I will be following with interest – look curiousprogrammer is (or at least was at the time of writing) the emacs featured blog on wordpress!

Read Full Post »

Following my earlier tests, I’ve got good hopes for Plack on Windows. To ramp it up from the hello world example I thought I’d try a simple network cache. HTTP isn’t obviously the best protocol for this purpose, but it’s widely used, presumably due to the existence of many robust servers (also maybe because people [including me of course!] can’t be bothered to check for short tcp reads/writes).

To make the example simple, I have (a) elided the actual call to retrieve the data and (b) put all of the code in one file. Obviously I wouldn’t recommend doing this in production but hopefully it will convey the intent.

# —

Most of my perl starts with a preamble that looks somewhat like this.

use 5.010;

use strict;
use warnings;

use POSIX;

get_data represents a call (to a database for example) that will take a while to complete.

sub get_data
{
    my $key = shift;
    sleep 5;
    return "[$key]";
}

get_cached_data is also very much simplified. Normally I’d expect to use something like the Cache::XXX modules.

sub get_cached_data
{
    my $key = shift;
    state %cache;

    if (! exists($cache{$key})) {
        $cache{$key} = get_data($key);
    }

    return $cache{$key};
}

response wraps the PSGI response to make the example a bit cleaner. It obviously wouldn’t be appropriate if other http response types were returned.

sub response
{
    my $data = shift;

    return [
        200,
        ['Content-Type' => 'text/plain'],
        [$data],
    ];
}

Twiggy doesn’t log the information about the request by default in the same way as plackup does. There may be a flag to enable that (should look at the code) but for now I synthesise it from $env.

sub request_info
{
    my $env = shift;
    my $ts = POSIX::strftime('%d/%b/%Y %H:%M:%S', localtime(time()));

    return qq{$env->{REMOTE_ADDR} - - [$ts] }
         . qq{"$env->{REQUEST_METHOD} $env->{PATH_INFO} $env->{SERVER_PROTOCOL}" }
         . qq{"-" "$env->{HTTP_USER_AGENT}"};
}

And there should be nothing surprising in the main.

# -- main

my $app = sub {
    my $env = shift;

    # foreach my $key (keys %$env) {
    #     print "$key $env->{$key}\n";
    # }

    # Twiggy doesn't give the same request info as vanilla plack
    say request_info($env);

    # Could map METHOD/PATH to subroutine calls using a hash
    my $method = $env->{REQUEST_METHOD};
    my $path_info = $env->{PATH_INFO};

    my $start = time();
    my $response = response(get_cached_data($path_info));
    my $time = time() - $start;
    my $s = ($time == 1) ? '' : 's';
    say "Generating response took $time second$s";

    return $response;
};

Testing with firefox is a bit crufty, but I haven’t got around to adapting my test client yet.

$ twiggy --listen :8080 obj-cache.psgi
127.0.0.1 - - [30/Mar/2010 21:24:47] "GET /someurl/ HTTP/1.1" "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 (.NET CLR 3.5.30729)"
Generating response took 5 seconds
127.0.0.1 - - [30/Mar/2010 21:25:02] "GET /someurl/ HTTP/1.1" "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 (.NET CLR 3.5.30729)"
Generating response took 0 seconds # Yes, looks good!

Read Full Post »

Okay, so down to business. One thing I like about straight cgi vs mod_perl is that any changes are immediately reflected on page refresh. And plackup (and twiggy) both offer an option to auto-restart when files change. Sounds good.

jared@win32 $ plackup -h
...
-r, --reload
        Make plackup to watch updates from your development directory and
        restarts the server whenever a file is updated. This option by
        default watches the "lib" directory and the base directory where
        *.psgi* file is located. Use "-R" if you want to watch other
        directories.
...
jared@win32 $ twiggy -r --listen :8080 hello.psgi
Watching ./lib hello.psgi for file updates.
./lib: No such file or directory at c:/strawberry/perl/site/lib/Filesys/Notify/Simple.pm line 156
Terminating on signal SIGINT(2)

Hmmm… I didn’t ask it to watch ./lib (and it doesn’t acknowledge changes to hello.psgi). Let me change the watched files with -R.

jared@win32 $ plackup -r -R hello.psgi --listen :8080 hello.psgi
HTTP::Server::PSGI: Accepting connections at http://0:8080/
Watching hello.psgi ./lib hello.psgi for file updates.
./lib: No such file or directory at c:/strawberry/perl/site/lib/Filesys/Notify/Simple.pm line 156
Terminating on signal SIGINT(2)

Er, okay, -R only allows you to add paths. So there is not an obvious way of removing the paths that already exist. *sigh*. I submit to the inevitable.

jared@win32 $ mkdir lib
jared@win32 $ twiggy -r --listen :8080 hello.psgi
Watching ./lib hello.psgi for file updates.

So I make a change to hello.psgi and get the following:

-- C:\home\jared\plack-tests\hello.psgi updated.
Killing the existing server (pid:-2872)

Almost! But I’m missing the message that says it was able to restart the server.

waitpid($pid, 0);
warn "Successfully killed! Restarting the new server process.\n";

In actual fact, the process it claims it has killed is still running and I’m still able to connect to it. So I hack Restarter.pm a bit (more on that at the end).

jared@win32 $ twiggy -r --listen :8080 hello.psgi
Watching ./lib hello.psgi for file updates.
-- C:\home\jared\plack-tests\hello.psgi updated.
Killing the existing server (pid:-2156)
Successfully killed! Restarting the new server process.
bind: Unknown error at c:/strawberry/perl/site/lib/Twiggy/Server.pm line 71
    -L, --loader

Using plackup instead of twiggy works.

jared@win32 $ plackup -r --listen :8080 hello.psgi
HTTP::Server::PSGI: Accepting connections at http://0:8080/
Watching ./lib hello.psgi for file updates.
-- C:\home\jared\plack-tests\hello.psgi updated.
Killing the existing server (pid:-3544)
Successfully killed! Restarting the new server process.
HTTP::Server::PSGI: Accepting connections at http://0:8080/

Although having thought about it, maybe the Shotgun loader is what I really want.

jared@win32 $ twiggy --listen :8080 hello.psgi -L Shotgun
Attempt to free unreferenced scalar: SV 0x2c78b04,
Perl interpreter: 0x2400054 at
c:/strawberry/perl/site/lib/Plack/Loader/Shotgun.pm line 48.

Again, plackup works here where twiggy does not.

jared@win32 $ plackup --listen :8080 hello.psgi -L Shotgun
HTTP::Server::PSGI: Accepting connections at http://0:8080/
127.0.0.1 - - [22/Mar/2010 21:21:31] "GET / HTTP/1.1" 200 42 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)"
127.0.0.1 - - [22/Mar/2010 21:21:35] "GET /favicon.ico HTTP/1.1" 200 42 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)"
127.0.0.1 - - [22/Mar/2010 21:22:07] "GET / HTTP/1.1" 200 42 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)"

# –

And at the risk of getting pointed comments for using the KILL signal, here is the hack I made to Restarter.pm. (Hey, what can I do? My OS blows.)

--- Plack.orig/Loader/Restarter.pm      2010-03-22 20:50:16 +0000
+++ Plack/Loader/Restarter.pm   2010-03-22 21:31:06 +0000
@@ -37,6 +37,12 @@
     my $pid = $self->{pid} or return;
     warn "Killing the existing server (pid:$pid)\n";
     kill 'TERM' => $pid;
+
+    if (lc($^O) =~ /mswin32/) {
+        sleep 1;
+        kill 'KILL' => $pid;
+    }
+
     waitpid($pid, 0);
     warn "Successfully killed! Restarting the new server process.\n";
 }

Read Full Post »

Now I have my command prompt set up the way I like it, installing modules into strawberry perl from from cpan is easy. Okay, fine, it was easy before, but now I just need to run my batch file and type cpan.

Okay, so one of the things I’m interested in is running Plack on Windows. And Twiggy looks like the obvious choice for HTTP servers supporting PSGI – the benchmarks I looked at state it is the second most performant pure(ish)-perl option after Starman and Starman clearly states it isn’t supported on Windows. Does the fact that Twiggy doesn’t say that mean that it works?

c:\home\jared>cpan

cpan shell -- CPAN exploration and modules installation (v1.9452)
Enter 'h' for help.


cpan> install Plack::Handler::Twiggy

...

t/02_signals.t .......... skipped: Broken perl detected,
skipping tests.
t/03_child.t ............ skipped: Your perl interpreter
is badly BROKEN. Child watchers will not work, ever. Try
upgrading to a newer perl or a working perl (cygwin's perl
is known to work). If that is not an option, you should be
able to use the remaining functionality of AnyEvent, but
child watchers WILL NOT WORK.

...

Yikes! This was emitted when building AnyEvent (a pretty key part of Twiggy). It doesn’t sound good does it? It comes from the following test:

BEGIN {
   # check for broken perls
   if ($^O =~ /mswin32/i) {
      my $ok;
      local $SIG{CHLD} = sub { $ok = 1 };
      kill 'CHLD', 0;

      unless ($ok) {
         print <<EOF;
1..0 # SKIP Your perl interpreter is badly BROKEN. Child watchers will not work, ever. Try upgrading to a newer perl or a working perl (cygwin's perl is known to work). If that is not an option, you should be able to use the remaining functionality of AnyEvent, but child watchers WILL NOT WORK.
EOF
         exit 0;
      }
   }
}

Okay, so child watchers don’t work (whatever they are). Hopefully Twiggy doesn’t need ‘em. Let’s plough on regardless. This is the standard Hello World app.

my $app = sub {
    my $env = shift;
    return [
        200,
        ['Content-Type' => 'text/plain'],
        [ "Hello stranger from $env->{REMOTE_ADDR}!"],
    ];
};

And firing up twiggy works, at least for this simple example.

jared@win32 $ twiggy --listen :8080 hello.psgi

Read Full Post »

Follow

Get every new post delivered to your Inbox.