20 May 2012, 16:02

Migrating to PSGI/Plack

Have you heard of PSGI/Plack?

It’s that awesome Perl meta-webframework you’re looking for. Unfortuneately it’s not that easy to get started with because the documentation is a bit too euphoric. They talk about “superglue” and “duct tape for the web” but fall a bit short of explaining how to get started with it.

Shortcut: It you’re using one of the supported frameworks (like Catalyst oder CGI::Application 4.5+) you shouldn’t need to work about anything of this. How to get those running w/ PSGI is explained in sufficient details in various docs.

This post is for those who need to do it w/o an framework or want to know the internals. Well, I’m not going into great detail in this post, only the essentials.

  • What is PSGI? PSGI is a specification of a protocol spoken between a PSGI compliant Server and the WebApp. The WebApp is talking PSGI to it’s executing server and this server is talking whatever he likes to his downstream (e.g. HTTP, FCGI, …)
  • What is Plack? Plack is a set of tools implementing PSGI. It provides some PSGI compliant Server implementations on its own and help others building their PSGI servers. It’s also some kind of meta-framework (“middleware”) that implements such things like Session management, authentication and compression. You don’t have to use those features! You don’t even need to known that they are there, but if you want you can have a look.
  • What is $env? This is a HashRef containing the environment for your request? Why env, you ask? Well, probably because CGI get it’s parameters passed via the OS ‘environment’ and they just adopted that for PSGI.
  • What is the PSGI-triplet? Well, that’s just the name I gave to the data structure PSGI expects to get returned after a request has been processed. It contains the HTTP-Statuscode, an ArrayRef with the HTTP-Header pairs and an ArrayRef containing the Body.
So, how do I migrate my framework-less perl web application to being PSGI compliatnt?
  • Throw out CGI, CGI::Carp and possibly FCGI. You won’t be using them anymore. You’ll be using Plack::Request instead.
  • Make your App “persistence-compatible”. That means you’ll have to abandon any global (class) variables thats only valid for one request. Every class variable must be valid throughout the entire runtime of your serverĀ  (because your class is instantiated only once, at the PSGI-Servers startup. There are excpetions to this, but keep it as a rule of thumb). Every information that is only valid for one request must be passed between the methods. If you have much pass around put if into a custom request class or a HashRef.
  • Make sure your class has a method handling the request. You probably have that already, but you should name it ‘run’. It will get passed the $env. Use that directly or create your custom per-request data structure from there.
  • Remove any direct output to STDOUT. Make your app return the PSGI-triplet to the caller. Everywhere.
  • Create a webapp.psgi, see below for it’s content and possible a webapp.pl if you want to support plain old CGI.
  • plackup webapp.psgi
webapp.psgi

#!/usr/bin/perl
use strict;
use warnings;

use lib '../lib';

use MyApp::Web::Frontend;

# The important part here is to instantiate your WebApp Class before
# the closure is defined. Everything inside the sub is executed on each
# request. If you instantiate your class inside you'll loose any benefit
# you get by not using CGI.
my $Frontend = MyApp::Web::Frontend::->new();
my $app = sub {
    my $env = shift;

    return $Frontend->run($env);
};

webapp.pl

#!/usr/bin/perl
use strict;
use warnings;

# Warning: This script will only work properly when invoked with
# the correct environment. Plack::Loader tries to autodetect the
# proper server and will use CGI only if certain CGI environment
# variables are set. It will most specifically not work properly
# when run from the commandline.
use Plack::Loader;

my $app = Plack::Util::load_psgi("webapp.psgi");
Plack::Loader::->auto->run($app);

04 Apr 2012, 08:00

DBI_TRACE

If you happen to encounter strange DBI-connection-lost issues, like me, it’s worth to try out DBI_TRACE! DBI_TRACE=2=dbitrace.log perl yourdbiscript.pl

This will write a very, very, detailed and helpful logfile to the current directory. Helped me to identify a nasty fork()ing related bug.

For the record: I was experiencing some strange “connection to mysql server lost” issues with a single thread script (no forking either). After some time a colleague pointed me to the DBI_TRACE documentation and I found out that I was incorrectly using some library that did some work in a fork(). The problems began when this fork was finished since it closed all filehandles, including the one to the database server.

30 Jun 2011, 08:00

Perl UTF-8 Checklist aka Surviving the Perl Unicode Madness

Some time ago, when I wrote the first version of this post I thought I had mastered UTF-8/Unicode with Perl and MySQL. Sadly I was very, very wrong. So I had to revisit the topic and I’d like to share my findings in the hope that they can save some coders from going nuts.

First you should read “Why does modern Perl avoid UTF-8 by default?” on Stackoverflow, especially the top-voted answer. It is the best ressource on UTF-8 and Perl I’ve found so far.

The next stop would be “UTF8, Mysql, Perl and PHP” on gyford.com. Pay special attention on the “utf8::decode( $var ) unless utf8::is_utf8( $var );” part. However I’d suggest using Encode::decode and Encode::is_utf8 instead. The imporant lesson to take away here is that you still may need to “decode” the bytes coming from the database into Perls internal UTF-8 representation. Once Perl knows its dealing with UTF-8 it will probably handle them correctly. Unfortunately sometimes the conditional decode doesn’t work … in this cases you can try to decode the data w/o checking if it is already in UTF-8 first. Brave new world …

If you still need more advice I suggest the following links, in this order: