I manage several low-traffic websites sites. These sites use the classic 2-server Apache/mod_perl architecture. The front-end server is a light Apache instance hosting a WordPress blog. The heavy, back-end server is mod_perl-enabled Apache serving various web applications I’ve created.
To the best of my understanding, mod_perl/Apache can only set-up and cache a single database connection. Is that right? Only one database connection per mod_perl instance?
But my applications need to access several databases. All the databases are hosted on a single instance of MySQL. I’ve set it up to use that single cached database connection, and also distinguish requests from the different front-end domains. Lastly, I’m experiencing a problem using $r->push_handlers. Let me tell you about it and ask for your feedback. First, the set up.
My database server runs MySQL 5.7.16. I have a “common” database, yes, it’s literally called “common”, which stores data accessible to and shared by many of my apps. I created a database user with “Data” privileges on most of the databases, but none of the ‘structure”, “administration” or “resource limits” privileges. So this user can read and write data, but cannot change structure or grants.
Both my Apache instances are 2.4.28. mod_perl is 2.0.10. A huge shout out to Steve Hay and the whole community for all the great work keeping mod_perl vibrant and viable. I love using it.
All this runs in the Amazon cloud on a Amazon Linux instance.
Front-End Config
In the front-end server, I’ve configured mod_rewrite to route requests for any of my mod_perl applications to the back-end mod_perl server. To allow the mod_perl server to distinguish between front-end servers, I add the front-end hostname to the re-written URL. Here is the RewriteRule in the front-end Apache configuration file:
RewriteCond %{HTTP_HOST} (.*)
RewriteRule ^/(tips/.*)$ http://127.0.0.1:8080/%1/$1 [P,L]
The value of “%1” in the RewriteRule is populated with the front-end hostname by the RewriteCond. So an incoming request for
https://example.com/tips/linkedintips/RsNFFHtfZF
will be seen at the back-end server as
https://127.0.0.1:8080/example.com/tips/linkedintips/RsNFFHtfZF
Back-End Config
In the mod_perl-enabled Apache config file, I set up a common PostReadRequestHandler to do all the housekeeping associated with any and all application requests. Here is that Directive:
PerlPostReadRequestHandler My::Init
The startup.pl file is called by
PerlPostConfigRequire /path/to/conf/startup.pl
A use lib pragma in startup.pl tells mod_perl where to find all my homegrown modules.
I’ve created a Config.pm module having credentials to allow that single cached database connection to connect to the common database. In the startup.pl file, use Config qw(%config) makes those parameters available. A call to Apache::DBI->connect_on_init() makes the connection.
So now the mod_perl server has a cached database connection at start up.
The Request
When a request for one of my applications comes in, the front-end server rewrites it and passes it to mod_perl. The first handler, assigned in the mod_perl Apache config file, instantiates a $opts hashref using $r->pnotes, thus:
my $opts = {}; $r->pnotes('opts', $opts);
Then in subsequent handlers, $opts is recovered from the request object like this:
my $opts = $r->pnotes("opts");
On every request, My::Init parses the URI, and stores the path components into the hashref $opts->{uri} with keys host, app, page, attr, and value. None of my apps use URLs having more path components than this.
That’s the basic setup. I have a problem to ask you about, relating to using $r->push_handlers. Before I told you about my problem, I wanted to describe my architecture in a stand-alone post. But describing the problem might make this article rather too long. So I’ll write another article about that.