startup.pl instructions for mod_perl #357

Merged
merged 1 commit into from Jan 31, 2013
View
145 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
@miyagawa
miyagawa Jan 31, 2013

I need some clarification - is these startup.pl handling still optional? If so, keep the comment here to make it less confusing.

I don't want people reading the SYNOPSIS scared nor cargo cult code like this. It might be a better idea to just have a comment like "# Optionally preload apps with startup.pl. See below for STARTUP FILES" or something?

+
+ # 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