Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

startup.pl instructions for mod_perl #357

Merged
merged 1 commit into from Jan 31, 2013
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
145 changes: 140 additions & 5 deletions lib/Plack/Handler/Apache2.pm
Expand Up @@ -196,23 +196,41 @@ sub _handle_response {


__END__ __END__


=encoding UTF-8

=head1 NAME =head1 NAME


Plack::Handler::Apache2 - Apache 2.0 handlers to run PSGI application Plack::Handler::Apache2 - Apache 2.0 handlers to run PSGI application


=head1 SYNOPSIS =head1 SYNOPSIS


# in your httpd.conf
<Location /> <Location />
SetHandler perl-script SetHandler perl-script
PerlResponseHandler Plack::Handler::Apache2 PerlResponseHandler Plack::Handler::Apache2
PerlSetVar psgi_app /path/to/app.psgi PerlSetVar psgi_app /path/to/app.psgi
</Location> </Location>


# Optional, preload the application in the parent like startup.pl PerlPostConfigRequire /etc/httpd/startup.pl
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

<Perl>
use Plack::Handler::Apache2; # In your startup.pl
Plack::Handler::Apache2->preload("/path/to/app.psgi"); use Apache2::ServerUtil ();
</Perl>
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 =head1 DESCRIPTION


Expand All @@ -238,6 +256,123 @@ run your application.
Plack::Handler::Apache2->call_app($r, $app); 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 =head1 AUTHOR


Tatsuhiko Miyagawa Tatsuhiko Miyagawa
Expand Down