Permalink
Browse files

document how to preload apps in startup.pl

Add instructions for using a startup.pl file, checking the restart_count
to make sure the app doesn't load twice (thanks to avar for that info.)

Also document how to catch errors from app loading so that the server
still starts, how to detect dynamically loaded modules so that they
can be preloaded and add paths to @INC.
  • Loading branch information...
1 parent 94cf6bb commit a5dbc6a05727eac3b3601a7acbf1bae18089574f @rkitover committed Dec 19, 2012
Showing with 140 additions and 5 deletions.
  1. +140 −5 lib/Plack/Handler/Apache2.pm
@@ -196,23 +196,41 @@ sub _handle_response {
__END__
+=encoding UTF-8
+
=head1 NAME
Plack::Handler::Apache2 - Apache 2.0 handlers to run PSGI application
=head1 SYNOPSIS
+ # in your httpd.conf
<Location />
SetHandler perl-script
PerlResponseHandler Plack::Handler::Apache2
PerlSetVar psgi_app /path/to/app.psgi
</Location>
- # Optional, preload the application in the parent like startup.pl
- <Perl>
- use Plack::Handler::Apache2;
- Plack::Handler::Apache2->preload("/path/to/app.psgi");
- </Perl>
+ PerlPostConfigRequire /etc/httpd/startup.pl
+
+ # In your startup.pl
+ use Apache2::ServerUtil ();
+
+ BEGIN {
+ return unless Apache2::ServerUtil::restart_count() > 1;
+
+ require Plack::Handler::Apache2;
+
+ my @psgis = ('/path/to/app1.psgi', '/path/to/app2.psgi');
+
+ foreach my $psgi (@psgis) {
+ Plack::Handler::Apache2->preload($psgi);
+ }
+ }
+
+ 1;
+
+See L</STARTUP FILE> for more details on writing a C<startup.pl>.
=head1 DESCRIPTION
@@ -238,6 +256,123 @@ run your application.
Plack::Handler::Apache2->call_app($r, $app);
}
+=head1 STARTUP FILE
+
+See L<http://perl.apache.org/docs/2.0/user/handlers/server.html#Startup_File>
+for information on the C<startup.pl> file for preloading perl modules and your
+apps.
+
+Some things to keep in mind when writing this file:
+
+=over 4
+
+=item * multiple init phases
+
+You have to check that L<Apache2::ServerUtil/restart_count> is C<< > 1 >>,
+otherwise your app will load twice and the env vars you set with
+L<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 below as a template.
+
+Thanks to avar (Ævar Arnfjörð Bjarmason) for this info!
+
+=item * C<@INC>
+
+The C<startup.pl> file is a good place to add entries to your C<@INC>.
+Use L<lib> to add entries, they can be in your app or C<.psgi> as well, but if
+your modules are in a L<local::lib> or some such, you will need to add the path
+for anything to load.
+
+Alternately, if you follow the example below, you can use:
+
+ PerlSetEnv PERL5LIB /some/path
+
+or
+
+ PerlSwitches -I/some/path
+
+in your C<httpd.conf>, which will also work.
+
+=item * loading errors
+
+Any exceptions thrown in your C<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
+L</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 = $@ || 'Unknown Error';
+ # STDERR goes to the error_log
+ print STDERR "Failed to load psgi '$psgi': $error\n";
+ };
+ }
+
+
+=item * dynamically loaded modules
+
+Some modules load their dependencies at runtime via e.g. L<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 C<%INC> from a request to see if you are using
+any such modules and preload them in your C<startup.pl>.
+
+Another method is dumping the difference between the C<%INC> on process start
+and process exit (suggested by avar.) 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;
+ }
+ }
+
+=back
+
+Here is an example C<startup.pl>:
+
+ #!/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!
+
=head1 AUTHOR
Tatsuhiko Miyagawa

0 comments on commit a5dbc6a

Please sign in to comment.