Skip to content

PSGI file evaluation convention

mateu edited this page Dec 9, 2011 · 9 revisions

PSGI file evaluation convention

Current Plack's implementation of evaluating .psgi file contains a couple of undocumented best practices, which now some web frameworks rely on. This is a straw man discussion whether we should publish it as a part of PSGI specification.

What is a .psgi file

PSGI application is a Perl code reference, so whatever Perl server/handler can run the application quite easily. However, because it's not easy to pass around Perl's code ref from a command line tool, we also have a convention where we define and return PSGI application in .psgi file, much like WSGI's app.wsgi or Rack's config.ru.

Plack

In Plack, there's a load_psgi($file) function defined in Plack::Util. The gut of this function is just:

my $app = eval 'do $_file';

but there are some tricks and best practices we've seen, to make sure it works with many web frameworks.

Practices

Environment Variables

Some frameworks like Dancer and Mojolicious implement their own standalone web servers, and their app.pl is designed to run as a standalone web server when executed on its own, but should return the PSGI application when called in the PSGI context.

The convention used in Dancer and Mojolicious is to detect PLACK_ENV environment variable, which is normally set when launched from Plack utilities such as plackup. We realize that it is not ideal we use PLACK_* as a prefix here, since it should be implementation neutral.

Setting $0 to the file path

Some modules, most notably FindBin, rely on $0 to figure out the current file path. Setting $0 to the path of the .psgi file makes the following code DWIM:

# app.psgi
use FindBin;
use lib "$FindBin::Bin/lib";
use MyApp; 
MyApp->psgi_app;

Although setting $0 to the file path would break a code assuming the following:

if ($0 eq __FILE__) {
    # Oh I am running from the command line!
}

See also: [[http://bulknews.typepad.com/blog/2011/02/findbin-file-0-and-psgi-woes.html]]

Clear out @ARGV

We've seen some versions of Dancer scripts parse options from the global @ARGV, and silently fail only if called from Plack::Runner, but otherwise bail out when there are unknown options. It is a good idea to clear out @ARGV before evaluating the .psgi file.

See also: https://github.com/sukria/Dancer/issues/473

Package

It's debatable which package it should be evaluated in. The easiest one would be main, but Plack currently generates a random package under Plack::Sandbox::.

Lexical variables

Even when a file is evaluated using eval and do, the .psgi file could still access lexical variables in the scope. It is recommended for the server to isolate the lexical scope when evaluating the file.

Error checking

The compilation failure should just error out immediately. Also, if the return value from the .psgi file is not a CODE reference then it should report that and bail out as well. It is debatable whether it should support an object that overloads &{} - currently Plack does.

Now what

So there's a couple of tricks necessary to make sure that all frameworks return the PSGI application. I am wondering if these practices should be documented as an optional PSGI spec so the non-Plack PSGI web servers (such as uWSGI, mod_psgi etc.) can implement correctly, or just extract the load_psgi($file) implementation as a separate tiny (pure-perl, non-deps) distribution that anyone can depend on or include.

(Of course Plack is the reference implementation anyway, but Plack is not totally deps free as of this writing and there are reasons some implementations can't or don't like to depend on)

Comments

Comments? https://github.com/miyagawa/psgi-specs/issues/12