saberworks has asked for the wisdom of the Perl Monks concerning the following question:

We have a fairly large e-commerce application running on apache 1.3 and mod_perl. There is a lib directory with all our libraries which also includes a library called SiteConfig.pm which contains configuration information about the site (such as database connection info, site name, site URL, various paths, etc.).

My boss told me he wants me to install the application for three more domains. I'm not a server admin nor do I know that much about the internals of mod_perl. Our "server admin" who got us set up with mod_perl to begin with recommends sharing the library directory among the 4 sites running this application. Since the configuration information is stored in a module, which is in turn kept in memory by mod_perl, I forsee problems!

We now need at least four separate configuration modules, but mod_perl needs to somehow know which one to run depending on which site is making the request. Many of the other modules use SiteConfig; so if we made one module for each site we'd have to also copy all the modules.

We really want to keep all the modules (and other files) exactly the same except the config module and the various HTML templates because there will be scripts propogating our changes to CVS out to the four sites.

Unfortunately the guy who suggested sharing the library directory has disappeared and now I'm trying to figure out if there is a way to do this w/out copying the library directory 4 times. Any ideas?

Update: satchm0h suggested I provide more details about our apache setup. We have one apache installation running one instance of mod perl. There are multiple virtualhosts but currently only our "original" site runs the code in question. My task is to make the code run on an additional 3 domains. Preferably without running three more instances of apache. Currently our code is stored in CVS and one of my coworkers manually runs a patch on the live site roughly every two weeks which contains all our code updates. We have a separate server altogether running MySQL and we are using Apache::DBI, Apache::Session, and Apache::Registry. The code was originally (up until december) running as CGIs (very slowly until we migrated it to mod_perl). Thanks in advance.

Replies are listed 'Best First'.
Re: mod_perl and multiple installations of the same code
by brian_d_foy (Abbot) on Mar 16, 2005 at 18:57 UTC

    Are these four sites running on the same box?

    You have to re-jigger your modules so they don't have to know which host they are working for, or make SiteConfig smart enough to load the right things based on which host it's dealing with. SiteConfig might hold a hash of several configs and through an appropriate interface, return the values for the right host.

    This is a basic mod_perl trap: you can't rely on Perl to clean up dependencies because it doesn't stop running. The design things you could ignore previously, perhaps setting global variables in a module and use-ing it, don't work anymore. We can't guess any more than that without knowing something about SiteConfig.pm

    This problem is solvable, though, without copying the libraries a bunch of times. It might take a little work, but that work is better than making the situation even worse. :)

      SiteConfig.pm is very simple. Here is an example:
      package SiteConfig; use strict; use Exporter; our $c; @SiteConfig::ISA = qw(Exporter); @SiteConfig::EXPORT_OK = qw($c); $c->{dbname} = 'somedb'; $c->{dbserver} = 'somehost'; $c->{dbuser} = 'someuser'; $c->{dbpass} = 'somepass'; $c->{site_name} = 'Some Plain Text Name'; $c->{domain} = 'some-domain.com'; #... and a bunch more ...
      Then the other various modules say stuff like: use SiteConfig qw($c); So what would need to happen is that SiteConfig would have to export a "$c" that is appropriate for the current request (based on some way to determine which of four domains it's serving). That doesn't even seem possible (to export something different at run-time when it's loaded when mod_perl starts). I think we'd have to change the interface from Exporter to a function or method call (in every one of our modules). There is also one "quick access" method inside SiteConfig.pm that allows you to grab any value w/out importing $c:
      sub param { return $c->{(shift)}; }
      That one seems like it would be easy to modify to return the appropriate value, if only I knew some reliable way to determine from which domain the request was coming.
        So what would need to happen is that SiteConfig would have to export a "$c" that is appropriate for the current request (based on some way to determine which of four domains it's serving). That doesn't even seem possible (to export something different at run-time when it's loaded when mod_perl starts).
        Tied variables allow you to have things that appear to be variables but are in fact subroutines.
        package SiteConfig; use strict; use base 'Exporter'; tie our $c, 'SiteConfig'; our @EXPORT_OK = qw($c); sub FETCH {{ dbname => 'somedb', dbserver => 'somehost', dbuser => 'someuser', dbpass => 'somepass', site_name => 'Some Plain Text Name', domain => 'some-domain.com', #... and a bunch more ... }}
        Running under mod_perl, you should be able to get an Apache::Request object easily, using something like this:
        # $c = { 'foo.com' => { dbname => 'foo', dbuser => 'foo', }, 'bar.com' => { dbname => 'bar', dbuser => 'bar', } }; sub param { my $param = shift; # get a request instance my $r = Apache::Request->instance(); # get the hostname my $host = $r->hostname(); return $c->{$host}->{$param}; }
        This obviously doesn't take into account 'www.foo.com' and 'foo.com' if they're the same thing, but a little munging of $host before using it, should allow you to find the right one, or worst case, fall back to a default.
Re: mod_perl and multiple installations of the same code
by dragonchild (Archbishop) on Mar 16, 2005 at 18:24 UTC
    What little you've described about your application architecture means that you will need to run 4 separate instances of mod_perl.

    It would be much better to abstract away the configuration into a cache somewhere, labelled by the application name, and each request goes and retrieves the configuration information for the application making the request. But, that requires rewriting some of your code. Hrmmm ... maybe 4 instances isn't so bad ...

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: mod_perl and multiple installations of the same code
by satchm0h (Beadle) on Mar 16, 2005 at 18:52 UTC
    First, I suggest you update your post to include a bit more information about your configuration. Are you using virtual servers within a single apache instance for the multiple domains? Are there multiple servers? Is all the "sharing" done via your automated CVS updating?

    Assuming you have separate installations and instances, I would think that the most sane approach would be to refactor your configuration management code to handle multiple configuration instances within the SiteConfig.pm package based on some key provided at load time. So you would have distinct configurations for each domain all stored (or at least referenced) in the SiteConfig. Then load the appropriate one into the global structure at run-time.