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.
|