Commit 21920a62 authored by Dietmar Maurer's avatar Dietmar Maurer

implement signal handler for clean reload/restart

parent 4b73743a
......@@ -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,6 +447,30 @@ 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,10 +764,14 @@ sub terminate_server {
worker_finished ($pid);
}
}
alarm(0); # avoid race condition
};
my $err = $@;
alarm ($previous_alarm);
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)) {
......@@ -763,7 +780,7 @@ sub terminate_server {
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");
}
......
......@@ -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);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment