]> git.proxmox.com Git - pve-manager.git/commitdiff
implement signal handler for clean reload/restart
authorDietmar Maurer <dietmar@proxmox.com>
Wed, 10 Apr 2013 09:06:08 +0000 (11:06 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Wed, 10 Apr 2013 09:12:03 +0000 (11:12 +0200)
PVE/APIDaemon.pm
bin/pveproxy

index f24f8f3ff55748c931ada50155bc679ba9c5e705..49ff03a31dd94919a8ecf58f1d8893096aad920b 100755 (executable)
@@ -13,6 +13,7 @@ use AnyEvent::TLS;
 use AnyEvent::IO;
 use Fcntl ();
 use Compress::Zlib;
+use PVE::SafeSyslog;
 
 use Scalar::Util qw/weaken/; # fixme: remove?
 use Data::Dumper; # fixme: remove
@@ -446,7 +447,31 @@ sub accept {
     return $clientfh;
 }
 
+sub wait_end_loop {
+    my ($self) = @_;
+
+    $self->{end_loop} = 1;
+
+    undef $self->{socket_watch};
+       
+    if ($self->{conn_count} <= 0) {
+       $self->{end_cond}->send(1);
+       return;
+    }
 
+    # else we need to wait until all open connections gets closed
+    my $w; $w = AnyEvent->timer (after => 1, interval => 1, cb => sub {
+       eval {
+           # fixme: test for active connections instead?
+           if ($self->{conn_count} <= 0) {
+               undef $w;
+               $self->{end_cond}->send(1);
+           }
+       };
+       warn $@ if $@;
+    });
+}
 sub accept_connections {
     my ($self) = @_;
 
@@ -495,27 +520,7 @@ sub accept_connections {
        $self->{end_loop} = 1;
     }
 
-    if ($self->{end_loop}) {
-       
-       undef $self->{socket_watch};
-       
-       if ($self->{conn_count} <= 0) {
-           $self->{end_cond}->send(1);
-           return;
-       }
-
-       # else we need to wait until all open connections gets closed
-       my $w; $w = AnyEvent->timer (after => 1, interval => 1, cb => sub {
-           eval {
-               # fixme: test for active connections instead?
-               if ($self->{conn_count} <= 0) {
-                   undef $w;
-                   $self->{end_cond}->send(1);
-               }
-           };
-           warn $@ if $@;
-       });
-    }
+    $self->wait_end_loop() if $self->{end_loop};
 }
 
 sub open_access_log {
@@ -534,7 +539,7 @@ sub open_access_log {
            syslog('err', "error writing access log: $msg");
            delete $self->{loghdl};
            $hdl->destroy;
-           $self->end_loop = 1; # terminate asap
+           $self->{end_loop} = 1; # terminate asap
        });;
 
     return;
@@ -545,7 +550,7 @@ sub new {
 
     my $class = ref($this) || $this;
 
-    foreach my $req (qw(cb socket lockfh lockfile end_cond)) {
+    foreach my $req (qw(cb socket lockfh lockfile)) {
        die "misssing required argument '$req'" if !defined($args{$req});
     }
 
@@ -562,6 +567,8 @@ sub new {
     $self->{max_requests} = 8000 if !$self->{max_requests};
 
 
+    $self->{end_cond} = AnyEvent->condvar;
+
     if ($self->{ssl}) {
        $self->{tls_ctx} = AnyEvent::TLS->new(%{$self->{ssl}}); 
     }
@@ -585,9 +592,25 @@ sub new {
        warn $@ if $@;
     });
 
+    $self->{term_watch} = AnyEvent->signal(signal => "TERM", cb => sub {
+       undef $self->{term_watch};
+       $self->wait_end_loop();
+    });
+
+    $self->{quit_watch} = AnyEvent->signal(signal => "QUIT", cb => sub { 
+       undef $self->{quit_watch};
+       $self->wait_end_loop();
+    });
+
     return $self;
 }
 
+sub run {
+    my ($self) = @_;
+
+    $self->{end_cond}->recv;
+}
+
 package PVE::APIDaemon;
 
 use strict;
@@ -611,6 +634,7 @@ use PVE::REST;
 use JSON;
 
 # DOS attack prevention
+# fixme: remove CGI.pm
 $CGI::DISABLE_UPLOADS = 1; # no uploads
 $CGI::POST_MAX = 1024 * 10; # max 10K posts
 
@@ -618,11 +642,6 @@ my $documentroot = "/usr/share/pve-api/root";
 
 my $workers = {};
 
-# some global vars
-# fixme: implement signals correctly
-my $child_terminate = 0;
-my $child_reload_config = 0;
-
 sub enable_debug { PVE::REST::enable_debug(); }
 sub debug_msg { PVE::REST::debug_msg(@_); }
 
@@ -709,13 +728,7 @@ sub start_workers {
        } else {
            $0 = "$0 worker";
 
-           $SIG{TERM} = $SIG{QUIT} = sub {
-               $child_terminate = 1;
-           };
-
-           $SIG{USR1} = sub {
-               $child_reload_config = 1;
-           };
+           $SIG{TERM} = $SIG{QUIT} = 'DEFAULT'; # we handle that with AnyEvent
 
            eval {
                # try to init inotify
@@ -743,7 +756,7 @@ sub terminate_server {
     # nicely shutdown childs (give them max 10 seconds to shut down)
     my $previous_alarm = alarm (10);
     eval {
-       local $SIG{ALRM} = sub { die "Timed Out!\n" };
+       local $SIG{ALRM} = sub { die "timeout\n" };
        
        while ((my $pid = waitpid (-1, 0)) > 0) {
            if (defined($workers->{$pid})) {
@@ -751,19 +764,23 @@ sub terminate_server {
                worker_finished ($pid);
            }
        }
-
+       alarm(0); # avoid race condition
     };
+    my $err = $@;
+    
     alarm ($previous_alarm);
 
-    foreach my $cpid (keys %$workers) {
-       # KILL childs still alive!
-       if (kill (0, $cpid)) {
-           delete ($workers->{$cpid});
-           syslog("err", "kill worker $cpid");
-           kill (9, $cpid);
+    if ($err) {
+       syslog('err', "error stopping workers (will kill them now) - $err"); 
+       foreach my $cpid (keys %$workers) {
+           # KILL childs still alive!
+           if (kill (0, $cpid)) {
+               delete ($workers->{$cpid});
+               syslog("err", "kill worker $cpid");
+               kill (9, $cpid);
+           }
        }
     }
-
 }
 
 sub start_server {
@@ -790,12 +807,10 @@ sub start_server {
            &$old_sig_term(@_) if $old_sig_term;
        };
 
-       local $SIG{USR1} = 'IGNORE';
-
        local $SIG{HUP} = sub {
            syslog("info", "received reload request");
            foreach my $cpid (keys %$workers) {
-               kill (10, $cpid); # SIGUSR1 childs
+               kill (15, $cpid); # kill childs
            }
        };
 
@@ -852,9 +867,7 @@ my $extract_params = sub {
 sub handle_connections {
     my ($self, $rpcenv) = @_;
 
-    my $end_cond = AnyEvent->condvar;
-
-    my $server = PVE::HTTPServer->new(%{$self->{cfg}}, end_cond => $end_cond, cb => sub {
+    my $server = PVE::HTTPServer->new(%{$self->{cfg}}, cb => sub {
        my ($server, $r) = @_;
 
        my $method = $r->method();
@@ -910,7 +923,7 @@ sub handle_connections {
     });
 
     debug_msg("wating for connections");
-    $end_cond->recv;
+    $server->run();
     debug_msg("end worker loop");
 }
 
index 05a89d10652588adc5c8220a4dab3e182dcac20b..a94bf60ba7cc617591b01473be610016ba25984a 100755 (executable)
@@ -12,7 +12,6 @@ use POSIX ":sys_wait_h";
 use Socket;
 use IO::Socket::INET;
 use PVE::SafeSyslog;
-# use PVE::Config; # fixme
 use PVE::APIDaemon;
 use HTTP::Response;
 use Encode;
@@ -125,7 +124,7 @@ if ($opt_debug || !($cpid = fork ())) {
 
        $SIG{INT} = 'DEFAULT';
 
-       unlink "$pidfile";
+       unlink "$pidfile" if !$opt_debug;
 
        exit (0);
     };