views:

482

answers:

1

Environment: Apache/2.2.11 (Win32) mod_apreq2-20051231/2.6.2-dev mod_perl/2.0.4-dev Perl/v5.10.0

Situation very similar to what's described in this discussion list post, except for being on win32.

I have this in httpd.conf:

PerlModule Apache2::Reload
PerlInitHandler Apache2::Reload
PerlSetVar ReloadAll Off
PerlSetVar ReloadModules "MyPackage::*"

...as well as only mod-perl script handling.

I have a script that uses a MyPackage module, and it's working.

I break the module, and reload the script. The error is a helpful one, telling the line where I broke the module.

(If I reload again at this point, and it only tells me "Undefined subroutine &ModPerl::ROOT::ModPerl::Registry..." because it wasn't able to load the file the first time. But either way the following behaviour still happens.)

I revert the break, and touch the script file too so it'll reload the module, and reload. Now it says:

Attempt to reload MyPackage/Foo.pm aborted.
Compilation failed in require at E:/dev/test.pl line 4.

And even if I touch the script and the module, I cannot get it to reload correctly, except by restarting the web server.

Breaking just the script itself (as opposed to the module) works fine: proper errors and changing it back results in it working again upon reload.

After each of these things I restarted the web server before testing:

  1. I've tried doing a trace, but the line that it continues to error out on is ModPerl/RegistryCooker.pm line 204, which is just the line that eval{}s the whole script.

  2. I've tried changing "use warnings FATAL => 'all'" to just "use warnings" in the script and the module. Didn't make a difference.

  3. I've tried disabling my custom $SIG{__DIE__} function. Didn't make a difference. (Well, only in where the error appeared, of course, but the errors generated were the same.)

  4. Per the discussion link at the beginning, found that MaxRequestsPerChild has been 0 this whole time, and I tried ThreadsPerChild 1, but no difference. I tried MaxRequestsPerChild to 1, which solves the weird behaviours of this question, but restarts the web server after every single request:

    Child 7072: Process exiting because it reached MaxRequestsPerChild. Signaling the parent to restart a new child process.
    Parent: Received restart signal -- Restarting the server.
    

    This isn't a good solution, since I have a significant chunk of code that's run the first time a page is hit.

  5. Also per the discussion, I run httpd as a service, so I added -X in the service parameters window and hit Start, and it was still trying to start a full three minutes later (usually starts within 3 seconds.) Even got a timeout message. Killed process via task manager and verified I couldn't hit the page from a web browser. Started httpd -X from the command line. Still the same behaviour as at the top of this question. Also I found it odd that -X was not listed when I ran httpd -?. Maybe it's not available on the win32 MPM?

  6. In that thread, David notes:

    My experience troubleshooting this kind of issue has indicated that its likely that the package that was unloaded deleted a value stored in the package space of the module reloaded (probably set at BEGIN block time) that the subsequent require did not restore.

    But this isn't true of my code. The 'break the script' error I introduce is just adding an extra 'my $var' line above one that's already there, so that the second one will complain that it's already been declared.

Is there no way to work on mod_perl2 modules without having the web server restart after every reload (whether automatically, via MaxRequestsPerChild, or manually, as before)?

+1  A: 

Copy the sub to the script you're calling it from, and put this code before the copy:

package MyPackage::Foo;
no warnings 'redefine';

When you're done making changes, move the sub back to the actual module.

Kev
You do have to restart after copying it back (sometimes!) but it's helpful until then, anyway.
Kev