Plack::Handler::Apache2(3) Apache 2.0 mod_perl handler to run PSGI application

SYNOPSIS


# in your httpd.conf
<Location />
SetHandler perl-script
PerlResponseHandler Plack::Handler::Apache2
PerlSetVar psgi_app /path/to/app.psgi
</Location>
# Optionally preload your apps in startup
PerlPostConfigRequire /etc/httpd/startup.pl

See ``STARTUP FILE'' for more details on writing a "startup.pl".

DESCRIPTION

This is a mod_perl handler module to run any PSGI application with mod_perl on Apache 2.x.

If you want to run PSGI applications behind Apache instead of using mod_perl, see Plack::Handler::FCGI to run with FastCGI, or use standalone HTTP servers such as Starman or Starlet proxied with mod_proxy.

CREATING CUSTOM HANDLER

If you want to create a custom handler that loads or creates PSGI applications using other means than loading from ".psgi" files, you can create your own handler class and use "call_app" class method to run your application.

  package My::ModPerl::Handler;
  use Plack::Handler::Apache2;
  sub get_app {
    # magic!
  }
  sub handler {
    my $r = shift;
    my $app = get_app();
    Plack::Handler::Apache2->call_app($r, $app);
  }

STARTUP FILE

Here is an example "startup.pl" to preload PSGI applications:

    #!/usr/bin/env perl
    use strict;
    use warnings;
    use Apache2::ServerUtil ();
    BEGIN {
        return unless Apache2::ServerUtil::restart_count() > 1;
        require lib;
        lib->import('/path/to/my/perl/libs');
        require Plack::Handler::Apache2;
        my @psgis = ('/path/to/app1.psgi', '/path/to/app2.psgi');
        foreach my $psgi (@psgis) {
            Plack::Handler::Apache2->preload($psgi);
        }
    }
    1; # file must return true!

See <http://perl.apache.org/docs/2.0/user/handlers/server.html#Startup_File> for general information on the "startup.pl" file for preloading perl modules and your apps.

Some things to keep in mind when writing this file:

  • multiple init phases

    You have to check that ``restart_count'' in Apache2::ServerUtil is "> 1", otherwise your app will load twice and the env vars you set with PerlSetEnv <http://perl.apache.org/docs/2.0/user/config/config.html#C_PerlSetEnv_> will not be available when your app is loading the first time.

    Use the example above as a template.

  • @INC

    The "startup.pl" file is a good place to add entries to your @INC. Use lib to add entries, they can be in your app or ".psgi" as well, but if your modules are in a local::lib or some such, you will need to add the path for anything to load.

    Alternately, if you follow the example above, you can use:

        PerlSetEnv PERL5LIB /some/path
    

    or

        PerlSwitches -I/some/path
    

    in your "httpd.conf", which will also work.

  • loading errors

    Any exceptions thrown in your "startup.pl" will stop Apache from starting at all.

    You probably don't want a stray syntax error to bring your whole server down in a shared or development environment, in which case it's a good idea to wrap the ``preload'' call in an eval, using something like this:

        require Plack::Handler::Apache2;
        my @psgis = ('/path/to/app1.psgi', '/path/to/app2.psgi');
        foreach my $psgi (@psgis) {
            eval {
                Plack::Handler::Apache2->preload($psgi); 1;
            } or do {
                my $error = [email protected] || 'Unknown Error';
                # STDERR goes to the error_log
                print STDERR "Failed to load psgi '$psgi': $error\n";
            };
        }
    
  • dynamically loaded modules

    Some modules load their dependencies at runtime via e.g. Class::Load. These modules will not get preloaded into your parent process by just including the app/module you are using.

    As an optimization, you can dump %INC from a request to see if you are using any such modules and preload them in your "startup.pl".

    Another method is dumping the difference between the %INC on process start and process exit. You can use something like this to accomplish this:

        my $start_inc = { %INC };
        END {
            my @m;
            foreach my $m (keys %INC) {
                push @m, $m unless exists $start_inc->{$m};
            }
            if (@m) {
                # STDERR goes to the error_log
                print STDERR "The following modules need to be preloaded:\n";
                print STDERR "$_\n" for @m;
            }
        }
    

AUTHOR

Tatsuhiko Miyagawa

CONTRIBUTORS

Paul Driver

AEvar Arnfjo.rd- Bjarmason

Rafael Kitover