-
Notifications
You must be signed in to change notification settings - Fork 33
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.
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
.
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.
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.
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]]
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
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::.
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.
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.
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? https://github.com/miyagawa/psgi-specs/issues/12