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

Hi Monks, I've got a mod_perl handler below...

<Location /session> SetHandler modperl PerlResponseHandler JSON::RPC::Server::Apache PerlSetVar dispatch "Handler::API::Session" PerlSetVar return_die_message 1 </Location>


In the handler, I call some class methods of a module that has a global database handle (to retain a persistent connection). I know I could use Apache::DBI but had some problems, and there shouldn't be any issues with keeping a dbh in a modules' namespace for re-use by any methods in that module.

The handler then does a couple of forks for the children to do some simultaneous actions, all of this works fine-ish. They do a CORE::exit once they've written data back to the parent.

I am however seeing some really strange behaviour, could this be caused by the dbh being copied to all children, then when they close they mess up the parent's one?

After giving apache a battering with Apache Benchmark, then trying a manual call, I see that when calling the handler, the process runs fine, but the time taken is reported as if it's the end of a previous process, ie, it completes in seconds when tailling the logs, but states it took 120 seconds.

I'm timing the handler with Time::HiRes::gettimeofday().

Any advice would be great, it's a really strange problem that I'm pulling my hair out over.

Cheers

Replies are listed 'Best First'.
Re: mod_perl, dbh, forked
by kyle (Abbot) on Mar 07, 2008 at 20:18 UTC

    Some of the things perrin mentions are discussed in a little more detail in DBI, fork, and clone.

    could this be caused by the dbh being copied to all children, then when they close they mess up the parent's one?

    Yes, this will happen.

Re: mod_perl, dbh, forked
by perrin (Chancellor) on Mar 07, 2008 at 20:09 UTC
    there shouldn't be any issues with keeping a dbh in a modules' namespace for re-use by any methods in that module
    Yes there should. Don't do that unless you're prepared to handle all the contingencies. Nearly everyone should be able to use Apache::DBI or DBI->connect_cached. If you need help with those, please ask.

    What's the strange behavior you see when you fork? Just anomalies in your time logs, or something else?

    One thing to watch out for is that many databases will call server-side cleanup routines when a dbh is closed or times out. You can control this with InactiveDestroy. You also typically need to open a new connection in the child, so if you're trying to keep using a connection opened in the parent, try making a new one instead.

      Thanks for the advice...

      I was using Apache::DBI originally and prob took it out for all the wrong reasons...

      I use my own database object to hold 2 connections to 2 different databases, live and readonly, I put a warn statement in my database object and the logs went nuts when I restart apache, for example:

      20 modules, each with 10 methods, each of which needs a dbh, starting 100 instances of apache means 20,000 connections! :-/

      I used a global db object for each module so that each method only connected unless it was already connected (with the global dbh)

      I don't want to pass in 1 dbh from each handler since the handler shouldn't know where the objects are getting their data.

      No doubt I missed another possible approach?

      The other strange behaviour was a query that selected 3 rows from a table, putting warn statements in showed that i was passing the correct things to the sth->execute() that would work, but occassionaly $sth->fetchrow_hashref() returned { '1' => 1 }.
        When you use Apache::DBI or DBI->connect_cached, they both keep a global cache of connections. They will not open a new one unless you use different parameters to open the connection, or the old connection has been disconnected.

        I haven't seen that fetchrow_hashref behavior before, but I don't actually use that method. If you don't have RaiseError turned on, definitely do that, since you may be missing errors earlier in the process.