简体   繁体   中英

How to shutdown Net::LDAP::Server

I have a Perl LDAP server which is based on the use Net::LDAP::Server module. To have it running as a service in Linux, I use the Net::Server::PreForkSimple library.

So far everything works fine, but when I shut the service down the child processes don't close.

What is the correct way to shut down all processes?

When I send a SIGTERM signal, the server_close method is called but nothing else happens. From this point on, terminated children are no longer restarted, but the children waiting for work are not terminated.

#!/usr/bin/perl

#chkconfig: 345 80 05
#description: LDAP Server for Innovaphone

use strict;
use warnings;

package Listener;

use Net::Server;
use base 'Net::Server::PreForkSimple';

my $continue = 1;

...

sub process_request {
    my $self = shift;

    my $in  = *STDIN{IO};
    my $out = *STDOUT{IO};

    my $sock         = $self->{server}->{client};
    my $peer_address = $sock->peerhost();
    my $peer_port    = $sock->peerport();
    logwarn( "Connection accepted from $peer_address : $peer_port" );

    my $handler = InnoLdapServer->new($sock);

    while ( 1 ) {
        my $finished = $handler->handle;
        return if $finished;
    }
}

...

sub server_close {
    logmsg( "Server close called" );
    $continue = 0;
}

# Start daemon
Proc::Daemon::Init();

my $pidfile = File::Pid->new({ file => "/var/run/inno-ldap.pid" });

if ( $pidfile->running() ) {
    die "Already running";
}

$pidfile->write();

open( STDOUT, '>', "$logpath/inno-ldap.$logName.log" ) or die "Can't open stdout log";
select( ( select( STDOUT ), $| = 1 )[0] );    # make the log file "hot" - turn off buffering

open( STDERR, '>', "$logpath/inno-ldap.$logName.error.log" ) or die "Can't open error log";
select( ( select( STDERR ), $| = 1 )[0] );    # make the log file "hot" - turn off buffering

while ( $continue ) {

    # package main;
    $roothandler = Listener->run(
        port          => [ 636, "389/tcp" ],
        proto         => "ssl",   # use ssl as the default
        ipv           => "*",     # bind both IPv4 and IPv6 interfaces
        user          => "daemon",
        group         => "daemon",
        SSL_key_file  => "/home/root/ssl_cert/server.pem",
        SSL_cert_file => "/home/root/ssl_cert/server.pem",
        max_servers   => 10,
        log_level     => 4
    );
}

$pidfile->remove();

1;

The shown code doesn't deal with the Net::Server itself, ie. its ::PreForkSimple extension; the server itself need be closed if the program is terminated by a signal. We can't see the calling code and how you " shut the service down ," other than by the mentioned signal.

There is a server_close method in Net::Server for this. But the method of the same name that the question refers to seems to be the one in your Listener class, which thus overrides the (grand)parent's method. It only stops further work in child processes and doesn't touch the server.

So if that's the method called in the signal handler then the server never gets shut down properly and its existing children stay around. You need to call server_close on a Net::Server object, or to arrange in your own server_close method to call the parent's one.

The Net::Server documentation under the Process Flow explains

During the server shutdown phase ( $self->server_close ), the following represents the program flow:

 $self->close_children; # if any $self->post_child_cleanup_hook; if (Restarting server) { $self->restart_close_hook(); $self->hup_server; } $self->shutdown_sockets; $self->server_exit; 

If the call to server_close on a Net::Server object or on the parent of your Listener object for some reason doesn't do it then try with individual methods listed in the workflow.

There are also signals listed in the Net::Server::PreForkSimple "personality" under Shutdown

Each of the Fork and PreFork personalities support graceful shutdowns via the QUIT signal. When a QUIT is received, the parent will signal the children and then wait for them to exit.

and then under Hot Deploy

Since version 2.000, the PreForkSimple server has accepted the TTIN and TTOU signals. When a TTIN is received, the max_servers is increased by 1. If a TTOU signal is received the max_servers is decreased by 1

But I'd hope that this shouldn't be needed for shutting it down, and certainly not the last one.

Changing the while (1) loop to while ($pidfile->running()) in process_request should do the trick. Setting $continue to zero prevents any more Listeners from running but from what I can tell, the process_request subroutine ignores that variable.

Of course, this will need $pidfile to be declared earlier as it wouldn't be in scope in process_request since it was declared (and assigned) after the subroutine definition.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM