如何在不重新启动的情况下调试 mod_perl2 模块?
环境:Apache/2.2.11 (Win32) mod_apreq2-20051231/2.6.2-dev mod_perl/2.0.4-dev Perl/v5.10.0
情况与 此讨论列表帖子,除了在 win32 上。
我在 httpd.conf 中有这个:
PerlModule Apache2::Reload
PerlInitHandler Apache2::Reload
PerlSetVar ReloadAll Off
PerlSetVar ReloadModules "MyPackage::*"
...以及仅 mod-perl 脚本处理。
我有一个使用 MyPackage 模块的脚本,并且它正在工作。
我破坏模块,然后重新加载脚本。 这个错误很有帮助,它告诉了我在哪里破坏了模块。
(如果我此时再次重新加载,它只会告诉我“未定义的子例程 &ModPerl::ROOT::ModPerl::Registry...”,因为它第一次无法加载该文件。但无论哪种方式以下行为仍然会发生。)
我恢复中断,并触摸脚本文件,以便它将重新加载模块,然后重新加载。 现在它说:
Attempt to reload MyPackage/Foo.pm aborted.
Compilation failed in require at E:/dev/test.pl line 4.
即使我触摸脚本和模块,我也无法让它正确重新加载,除非重新启动 Web 服务器。
仅破坏脚本本身(而不是模块)效果很好:正确的错误并将其改回会导致它在重新加载时再次工作。
在完成所有这些操作之后,我在测试之前重新启动了 Web 服务器:
我尝试过进行跟踪,但是 继续出错的行 位于 ModPerl/RegistryCooker.pm 行 204,这只是一行 eval{} 是整个脚本。
我尝试更改“使用警告 致命=> ‘全部’”只是“使用 脚本中的警告”和 模块。 没有什么区别。
我尝试过禁用我的自定义 $SIG{__DIE__} 函数。 没有 做出改变。 (嗯,只有在 当然,错误出现的地方 但产生的错误是 相同。)
根据开头的讨论链接,发现MaxRequestsPerChild一直为0,我尝试了ThreadsPerChild 1,但没有区别。 我尝试将 MaxRequestsPerChild 设置为 1,这解决了这个问题的奇怪行为,但在每个请求后都会重新启动 Web 服务器:
Child 7072:进程因达到 MaxRequestsPerChild 而退出。 向父进程发出信号以重新启动新的子进程。 父级:收到重启信号——正在重启服务器。
这不是一个好的解决方案,因为我有大量代码在第一次点击页面时运行。
另外,根据讨论,我将 httpd 作为服务运行,因此我在服务参数窗口中添加了 -X 并单击“开始”,但它仍然在整整三分钟后尝试启动(通常在 3 秒内启动。)收到超时消息。 通过任务管理器终止进程并验证我无法从网络浏览器访问该页面。 从命令行启动 httpd -X。 仍然与这个问题顶部的行为相同。 我还发现奇怪的是,当我运行 httpd -? 时,-X 没有列出。 也许它在 win32 MPM 上不可用?
在那条线索中,大卫指出:
<块引用>我解决此问题的经验 此类问题表明其 可能是那个包裹 unloaded 删除了存储在中的值 重新加载模块的包空间 (可能在 BEGIN 区块时间设置) 后续要求没有 恢复。
但我的代码并非如此。 我引入的“破坏脚本”错误只是在已有的一行上方添加了一个额外的“my $var”行,这样第二行就会抱怨它已经被声明了。
有没有办法在 mod_perl2 模块上工作而无需在每次重新加载后重新启动 Web 服务器(无论是通过 MaxRequestsPerChild 自动启动,还是像以前一样手动启动)?
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:
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.I've tried changing "use warnings
FATAL => 'all'" to just "use
warnings" in the script and the
module. Didn't make a difference.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.)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.
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?
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)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
将子复制到您从中调用它的脚本,并将此代码放在副本之前:
完成更改后,将子移回实际模块。
Copy the sub to the script you're calling it from, and put this code before the copy:
When you're done making changes, move the sub back to the actual module.