cgiapp


One of the things that attracts (some) people to CGI::Application is the availability to have stripped down super efficient web applications. One of the strengths of it (CA) is that it is versatile enough to provide different strengths to different people, so in fact, a good proportion of CA users don’t actually care about what I call lean programming — as long as you’re not doing anything fancy you can get away with creating everything for every request that comes in. So that’s why some users advocate ignoring efficiency in the early stages; CGI::Application is already a pretty lean perl application framework, so any deployment that works has a good chance of being fairly efficient.

However, it turns out there are other users who require and cater for lean programming, including many of the plugin authors. The technique is very simple — you put your persistent objects/data in class storage and your per-request objects/data in your per-request CA object. (There are many tweaks to that model, including using traditional RDBMS, no-sql tuple pools, memcache variants, CPAN wrapper modules, etc, but usually the simple flavour is all you need and is easy to implement in CGI::Application.) Look at the CGI::Application::Plugin::Authentication source code if you want to see an example of the inner workings, but that’s not necessary (and the logic flow is not terribly transparent in that plug-in). The pattern goes:

  1. Have a MyApp::Base which is a sub-class of CGI::Application and which all your MyApp (request handler) modules sub-class
  2. In that class, define your cgiapp_init method
  3. In cgiapp_init initialise all your application-wide configuration into class storage (eg %MyApp::Base::__Stash) using a guard to ensure you only do this once per perl interpreter:
    unless ($MyApp::Base::__Stash{config}) {
        $MyApp::Base::__Stash{config} = {};
        # Initialise application-wide values
        # Initialise plug-ins, using those values
        MyApp::Base->authen->config(
            # ...
        );
    }
    
  4. For each plug-in you use, check whether it caters for class access in addition to object access. eg for CGI::Application::Plugin::Authentication, use MyApp::Base->authen->config rather than $myapp->authen->config and it will do the rest for you.
  5. Then (still within your cgiapp_init) initialise any per-request data into your $myapp object:
        # Per-request initialisation
        $self->param(
            foo => 'bar',
            dbh => $MyApp::Base::__Stash{db_accessor}->connect,
            # ...
        );
    

You can take this further by ensuring as much as possible is done in the initial (parent) perl interpreter, for example doing initialisation before the first fork if using mod_perl2 with the ‘prefork’ MPM, but that’s the subject of a separate story.

Advertisements

This is an example “way of doing things” with CGI::Application. It can’t claim to be ‘best practice’ since there are some better sites out there that happen to do things differently. It’s mainly as a reminder to myself and collaborators of how things should hang together, but if you’re starting out with CGI::Application you could do a lot worse than to copy these suggestions; your aims and requirements will be at least a bit different, but it should be easy to extend or take these notes on a different tack.

Directory Layout

These would usually be under /srv/<app>

bin
Batch scripts (executed by sysadmin)
cfg
Configuration files. eg cfg/app.cnf
cgi
Apache-invoked files for where we can’t configure apache. eg cgi/app.cgi
data
Initialisation or run-time data that is kept in files
doc
Documentation for everything. eg doc/man/man3/Cari::Mysql.3pm.gz
lib
Third-party (upstream) modules. eg lib/Cari/Mysql.pm
log
Log files. eg log/app_err.log
mod/C
Application controller modules. egs mod/C/Mod1.pm, mod/C/Mod1/Submod1.pm
mod/M
Application model modules. eg mod/M/User.pm
mod/V
Application view modules. eg mod/V/Dropdown.pm
test
Test scripts
tmpl
Template files. eg tmpl/mod1/rm1.html
www
Static web-accessible files. eg www/favicon.ico
www/css
Style sheets. eg www/css/app.css
www/img
Icons and images. eg www/img/mod1/banner.jpg
www/js
Javascript. eg www/js/jquery-1.4.2.min.js