http://www.perlmonks.org?node_id=884361


in reply to Re^4: Stopping an HTTP::Server::Simple server
in thread Stopping an HTTP::Server::Simple server

Another possibility is that the op is trying to launch the webserver in one process invocation, and then kill it in another. In which case $pid will have to be written to/from a file.
  • Comment on Re^5: Stopping an HTTP::Server::Simple server

Replies are listed 'Best First'.
Re^6: Stopping an HTTP::Server::Simple server
by textual (Novice) on Jan 26, 2011 at 16:38 UTC
    Thanks a lot for your replies.

    Sorry, my previous answer was ambiguous: $pid is undefined in the handle_request () method of MyWebServer, but it is correctly set to something like "-1470" in test.pl.

    In fact, writing this in test.pl effectively stops the server immediately:
    use strict; use warnings; use MyWebServer; my $server = MyWebServer->new(8080); my $pid = $server->background(); kill 9, $pid;

    But in order to execute this instruction in response to some HTTP request, (I think) I need to call it from within a handler in MyWebServer.

    I find that the following:
    kill 9, $$;
    effectively stops the server if it is added anywhere in MyWebServer.pm's "body" (e.g. at the first line), but not if it is added in the handle_request() method.

    I've also tried tilly's suggestion to have test.pl write the PID in a file, then have handle_request() read this file. It does succeed at passing the PID, and I do not get the "Can't kill a non-numeric process ID" message anymore, however the call to kill does not stop the server in this case.

      If your server is non-forking, you should be able just call exit to stop the server. That will do the same thing as the kill line.

      If the server is forking under the hood, then in handling a web request you are just killing the child process that is handling that request and another will be spawned shortly. In that case you would need to kill some set of processes to shut it down. What set depends on how it is set up. For instance if it forks for every request received, then killing your parent process (which getppid should give you) will do it. If it preforks and has a pool of processes, then you need to kill them all. Typically you can do that by sending the right signal to the parent process.

      Given your described behavior, it sounds like it may be forking. (That, or kill -9 is failing somehow.)

        Thanks again for your help, which makes this site the unique resource it is.

        Using exit from within the handler does the job! This seems to be the natural solution I've failed to come up with. So in Webserver.pm:
        package MyWebServer; use strict; use warnings; use HTTP::Server::Simple::CGI; use base qw(HTTP::Server::Simple::CGI); sub handle_request { exit; } 1;

        For the sake of completeness, here's the code where the PID was written in a file (with some diagnostics sent to STDERR). Note that it didn't stop the server:

        In test.pl:
        use strict; use warnings; use MyWebServer; my $server = MyWebServer->new( 8080 ); my $pid = $server->background(); print STDERR $pid, "\n"; open( my $fh, '>', 'pid.txt' ) || die; print $fh $pid; close $fh;
        And in Webserver.pm:
        package MyWebServer; use strict; use warnings; use HTTP::Server::Simple::CGI; use base qw(HTTP::Server::Simple::CGI); sub handle_request { open( my $fh, '<', 'pid.txt' ) || die; my $pid = <$fh>; close $fh; print STDERR $pid, "\n"; kill 9, $pid; } 1;

      ->handle_request() will be called in a child process, so it's no surprise that $pid is undefined there (see previous discussion), as $pid is only set in the parent. kill 9, $$ only kills the child process, so that won't work either.

      You haven't shown the code that you used to write the PID to a file. You should show that code, or output more diagnostics while running your code to track what values $$ and $pid have at which time, and also what the values read from the .pid file are. Do you check for failure when opening the file in the child?