home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Practical mod_perlPractical mod_perlSearch this book

21.2. Debugging Code in Single-Server Mode

Normally, Apache runs one parent process and several children. The parent starts new child processes as required, logs errors, kills off child processes that have served MaxRequestsPerChild, etc. But it is the child processes that serve the actual requests from web browsers. Because the multiprocess model can get in your way when you're trying to find a bug, sometimes running the server in single-process mode (with -X) is very important for testing during the development phase.

You may want to test that your application correctly handles global variables, if you have any. It is best to have as few globals as possible—ideally none—but sometimes you just can't do without them. It's hard to test globals with multiple servers executing your code, since each child has a different set of values for its global variables.

Imagine that you have a random( )subroutine that returns a random number, and you have the following script:

use vars qw($num);
$num ||= random( );
print ++$num;

This script initializes the variable $num with a random value, then increments it on each request and prints it out. Running this script in a multiple-server environment will result in something like 1, 9, 4, 19 (a different number each time you hit the browser's reload button), since each time your script will be served by a different child. But if you run in httpd -X single-server mode, you will get 6, 7, 8, 9... assuming that random( ) returned 6 on the first call.

But do not get too obsessive with this mode—working in single-server mode sometimes hides problems that show up when you switch to normal (multiple-server) mode.

Consider an application that allows you to change the configuration at runtime. Let's say the script produces a form to change the background color of the page. This isn't good design, but for the sake of demonstrating the potential problem we will assume that our script doesn't write the changed background color to the disk—it simply stores it in memory, like this:

use CGI;
my $q = CGI->new( );
use vars qw($bgcolor);
$bgcolor ||= "white";
$bgcolor = $q->param('bgcolor') if $q->param('bgcolor');

where $bgcolor is set to a default "white" if it's not yet set (otherwise, the value from the previous setting is used). Now if a user request updates the color, the script updates the global variable.

So you have typed in "yellow" for the new background color, and in response, your script prints back the HTML with the background color yellow—you think that's it! If only it was so simple.

If you keep running in single-server mode you will never notice that you have a problem. However, if you run the same code in normal server mode, after you submit the color change you will get the result as expected, but when you call the same URL again (not via reload!) the chances are that you will get back the original default color (white, in this case). Only the child that processed the color-change request has its $bgcolor variable set to "yellow"; the rest still have "white". This shows that the design is incorrect—the information is stored in only one process, whereas many may be running.

Remember that children can't share information directly, except for data that they inherited from their parent when they were created and that hasn't subsequently been modified.

There are many solutions to this example problem: you could use a hidden HTML form variable for the color to be remembered, or store it in some more permanent place on the server side (a file or database), or you could use shared memory, and so on.

Note that when the server is running in single-process mode, and the response includes HTML with <img> tags, the loading of the images will take a long time for browsers that try to take an advantage of the KeepAlive feature (e.g., Netscape). These browsers try to open multiple connections and keep them open. Because there is only one server process listening, each connection has to finish before the next can start. Turn off KeepAlive in httpd.conf to avoid this effect. Alternatively (assuming that the image-size parameters are included, so that a browser will be able to render the rest of the page) you can press Stop after a few seconds.

In addition, you should be aware that when running with -X you will not see the status messages that the parent server normally writes to the error_log file ("Server started", "Server stopped", etc.). Since httpd -X causes the server to handle all requests itself, without forking any children, there is no controlling parent to write the status messages.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.