O'Reilly logo

Embedding Perl in HTML with Mason by Ken Williams, Dave Rolsky

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Developer Environments

Having a development environment is a good thing for many reasons. Testing potential changes on your production server is likely to get you fired, for one thing.

Ideally, you want each developer to have his own playground where changes he makes don’t affect others. Then, when something is working, it can be checked into source control and everyone else can use the updated version.

Multiple Component Roots

A fairly simple way to achieve this goal is by giving each developer his own component root, which will be checked before the main root.

Developers can work on components in their own private roots without fear of breaking anything for anyone else. Once changes are made, the altered component can be checked into source control and moved into the shared root, where everyone will see it.

This means that one HTML::Mason::ApacheHandler object needs to be created for each developer. This can be done solely by changing your server configuration file, but it is easiest to do this using an external handler.

The determination of which object to use can be made either by looking at the URL path or by using a different hostname for each developer.

By path

This example checks the URL to determine which developer’s private root to use:

use Apache::Constants qw(DECLINED);

my %ah;

sub handler {
    my $r = shift;
    my $uri = $r->uri;
    $uri =~ s,^/(\w+),,;  # remove the developer name from the path

    my $developer = $1 or return DECLINED;

    $r->uri($uri);  # set the uri to the new path

    $ah{$developer} ||=
      HTML::Mason::ApacheHandler->new
          ( comp_root => [ [ dev  => "/home/$developer/mason" ],
                           [ main => '/var/www' ] ],
            data_dir => "/home/$developer/data" );

    return $ah{$developer}->handle_request($r);
}

We first examine the URL of the request to find the developer name, which we assume will always be the first part of the path, like /faye/index.html. We use a regex to remove this from the URL, which we then change to be the altered path.

If there is no developer name we simply decline the request.

The main problem with this approach is that it would then require that all URLs on the site be relative in order to preserve the developer’s name in the path. In addition, some Apache features like index files and aliases won’t work properly either. Fortunately, there is an even better way.

By hostname

This example lets you give each developer their own hostname:

my %ah;

sub handler {
    my $r = shift;

    my ($developer) = $r->hostname =~ /^(\w+)\./;

    $ah{$developer} ||=
      HTML::Mason::ApacheHandler->new
          ( comp_root => [ [ dev  => "/home/$developer/mason" ],
                           [ main => '/var/www' ] ],
            data_dir => "/home/$developer/data" );

    return $ah{$developer}->handle_request($r);
}

This example assumes that for each developer there is a DNS entry like dave.dev.masonbook.com. You could also insert a CNAME wildcard entry in your DNS. The important part is that the first piece is the developer name.

Of course, with either method, developers will have to actively manage their development directories. Any component in their directories will block their access to a component of the same name in the main directory.

Multiple Server Configurations

The multiple component root method has several downsides:

  • Modules are shared by all the developers. If a change is made to a module, everybody will see it. This means that API changes are forced out to everyone at once, and a runtime error will affect all the developers. Additionally, you may need to stop and start the server every time a module is changed, interrupting everyone (although you could use Apache::Reload from CPAN to avoid this).

  • You can’t test different server configurations without all the developers being affected.

  • Truly catastrophic errors that bring down the web server affect everyone.

  • The logs are shared, so if you like to send messages to the error log for debugging you’d better hope that no one else is doing the same thing or you’ll have a mess.

The alternative is to run a separate daemon for each developer, each on its own port. This means maintaining either one fairly complicated configuration file, with a lot of <IfDefine> directives or separate configuration files for each developer.

The latter is probably preferable as it gives each developer total freedom to experiment. The configuration files can be generated from a template (possibly using Mason) or a script. Then each developer’s server can listen on a different hostname or port for requests.

You can have each server’s component root be the developer’s working directory, which should mirror the layout of the real site. This means that there is no need to tweak any paths in the components.

This method’s downside is that it will inevitably use up more memory than having a single server. It also requires a greater initial time investment in order to generate the configuration file templates. But the freedom it gives to individual developers is very nice, and the time investment is fixed.

Of course, since each developer has a computer, there is nothing to stop a developer from simply setting up Apache and mod_perl locally. And the automation would be even easier since there’s no need to worry about dealing with unique port numbers or shared system resources. Even better (or worse, depending on your point of view), a developer can check out the entire system onto a laptop and work on the code without needing to be on the office network.

Managing DBI Connections

Not infrequently, we see people on the Mason users list asking questions about how to handle caching DBI connections.

Our recipe for this is really simple:

use Apache::DBI

Rather than reinventing the wheel, use Apache::DBI , which provides the following features:

  • It is completely transparent to use. Once you’ve used it, you simply call DBI->connect( ) as always and Apache::DBI gives you an existing handle if one is available.

  • It makes sure that the handle is live, so that if your RDBMS goes down and then back up, your connections still work just fine.

  • It does not cache handles made before Apache forks, as many DBI drivers do not support using a handle after a fork.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required