mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-26 23:45:44 +00:00
Large refactoring of pt-agent to make the initial start up experience more reliable, i.e. just run and wait till a good config makes everything else work.
This commit is contained in:
974
bin/pt-agent
974
bin/pt-agent
File diff suppressed because it is too large
Load Diff
182
lib/Daemon.pm
182
lib/Daemon.pm
@@ -31,47 +31,24 @@ use Fcntl qw(:DEFAULT);
|
|||||||
sub new {
|
sub new {
|
||||||
my ($class, %args) = @_;
|
my ($class, %args) = @_;
|
||||||
my $self = {
|
my $self = {
|
||||||
log_file => $args{log_file},
|
log_file => $args{log_file},
|
||||||
pid_file => $args{pid_file},
|
pid_file => $args{pid_file},
|
||||||
daemonize => $args{daemonize},
|
daemonize => $args{daemonize},
|
||||||
|
force_log_file => $args{force_log_file},
|
||||||
};
|
};
|
||||||
return bless $self, $class;
|
return bless $self, $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub run {
|
sub run {
|
||||||
my ($self, %args) = @_;
|
my ($self) = @_;
|
||||||
my $pid ||= $PID;
|
|
||||||
my $pid_file ||= $self->{pid_file};
|
|
||||||
my $log_file ||= $self->{log_file};
|
|
||||||
|
|
||||||
if ( $self->{daemonize} ) {
|
# Just for brevity:
|
||||||
$self->_daemonize(
|
my $daemonize = $self->{daemonize};
|
||||||
pid => $pid,
|
my $pid_file = $self->{pid_file};
|
||||||
pid_file => $pid_file,
|
my $log_file = $self->{log_file};
|
||||||
log_file => $log_file,
|
my $force_log_file = $self->{force_log_file};
|
||||||
);
|
|
||||||
}
|
|
||||||
elsif ( $pid_file ) {
|
|
||||||
$self->_make_pid_file(
|
|
||||||
pid => $pid,
|
|
||||||
pid_file => $pid_file,
|
|
||||||
);
|
|
||||||
$self->{pid_file_owner} = $pid;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PTDEBUG && _d('Neither --daemonize nor --pid was specified');
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
PTDEBUG && _d('Starting daemon');
|
||||||
}
|
|
||||||
|
|
||||||
sub _daemonize {
|
|
||||||
my ($self, %args) = @_;
|
|
||||||
my $pid = $args{pid};
|
|
||||||
my $pid_file = $args{pid_file};
|
|
||||||
my $log_file = $args{log_file};
|
|
||||||
|
|
||||||
PTDEBUG && _d('Daemonizing');
|
|
||||||
|
|
||||||
# First obtain the pid file or die trying. NOTE: we're still the parent
|
# First obtain the pid file or die trying. NOTE: we're still the parent
|
||||||
# so the pid file will contain the parent's pid at first. This is done
|
# so the pid file will contain the parent's pid at first. This is done
|
||||||
@@ -82,93 +59,90 @@ sub _daemonize {
|
|||||||
if ( $pid_file ) {
|
if ( $pid_file ) {
|
||||||
eval {
|
eval {
|
||||||
$self->_make_pid_file(
|
$self->_make_pid_file(
|
||||||
pid => $pid, # parent's pid
|
pid => $PID, # parent's pid
|
||||||
pid_file => $pid_file,
|
pid_file => $pid_file,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
if ( $EVAL_ERROR ) {
|
die "$EVAL_ERROR\n" if $EVAL_ERROR;
|
||||||
die "Cannot daemonize: $EVAL_ERROR\n";
|
if ( !$daemonize ) {
|
||||||
|
# We're not going to daemonize, so mark the pid file as owned
|
||||||
|
# by the parent. Otherwise, daemonize/fork and the child will
|
||||||
|
# take ownership.
|
||||||
|
$self->{pid_file_owner} = $PID; # parent's pid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Fork, exit parent, continue as child process.
|
# Fork, exit parent, continue as child process.
|
||||||
defined (my $child_pid = fork())
|
if ( $daemonize ) {
|
||||||
or die "Cannot fork: $OS_ERROR";
|
defined (my $child_pid = fork()) or die "Cannot fork: $OS_ERROR";
|
||||||
if ( $child_pid ) {
|
if ( $child_pid ) {
|
||||||
# I'm the parent.
|
# I'm the parent.
|
||||||
PTDEBUG && _d('Forked child', $child_pid);
|
PTDEBUG && _d('Forked child', $child_pid);
|
||||||
exit 0;
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# I'm the child.
|
||||||
|
POSIX::setsid() or die "Cannot start a new session: $OS_ERROR";
|
||||||
|
chdir '/' or die "Cannot chdir to /: $OS_ERROR";
|
||||||
|
|
||||||
|
# Now update the pid file to contain the child's pid.
|
||||||
|
if ( $pid_file ) {
|
||||||
|
$self->_update_pid_file(
|
||||||
|
pid => $PID, # child's pid
|
||||||
|
pid_file => $pid_file,
|
||||||
|
);
|
||||||
|
$self->{pid_file_owner} = $PID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# I'm the child. First, open the log file, if any. Do this first
|
if ( $daemonize || $force_log_file ) {
|
||||||
# so that all daemon/child output goes there.
|
# We used to only reopen STDIN to /dev/null if it's a tty because
|
||||||
|
# otherwise it may be a pipe, in which case we didn't want to break
|
||||||
# We used to only reopen STDIN to /dev/null if it's a tty because
|
# it. However, Perl -t is not reliable. This is true and false on
|
||||||
# otherwise it may be a pipe, in which case we didn't want to break
|
# various boxes even when the same code is ran, or it depends on if
|
||||||
# it. However, Perl -t is not reliable. This is true and false on
|
# the code is ran via cron, Jenkins, etc. Since there should be no
|
||||||
# various boxes even when the same code is ran, or it depends on if
|
# sane reason to `foo | pt-tool --daemonize` for a tool that reads
|
||||||
# the code is ran via cron, Jenkins, etc. Since there should be no
|
# STDIN, we now just always close STDIN.
|
||||||
# sane reason to `foo | pt-tool --daemonize` for a tool that reads
|
PTDEBUG && _d('Redirecting STDIN to /dev/null');
|
||||||
# STDIN, we now just always close STDIN.
|
close STDIN;
|
||||||
PTDEBUG && _d('Redirecting STDIN to /dev/null');
|
open STDIN, '/dev/null'
|
||||||
close STDIN;
|
or die "Cannot reopen STDIN to /dev/null: $OS_ERROR";
|
||||||
open STDIN, '/dev/null'
|
if ( $log_file ) {
|
||||||
or die "Cannot reopen STDIN to /dev/null: $OS_ERROR";
|
PTDEBUG && _d('Redirecting STDOUT and STDERR to', $log_file);
|
||||||
if ( $log_file ) {
|
|
||||||
PTDEBUG && _d('Redirecting STDOUT and STDERR to', $log_file);
|
|
||||||
close STDOUT;
|
|
||||||
open STDOUT, '>>', $log_file
|
|
||||||
or die "Cannot open log file $log_file: $OS_ERROR";
|
|
||||||
|
|
||||||
# If we don't close STDERR explicitly, then prove Daemon.t fails
|
|
||||||
# because STDERR gets written before STDOUT even though we print
|
|
||||||
# to STDOUT first in the tests. I don't know why, but it's probably
|
|
||||||
# best that we just explicitly close all fds before reopening them.
|
|
||||||
close STDERR;
|
|
||||||
open STDERR, ">&STDOUT"
|
|
||||||
or die "Cannot dupe STDERR to STDOUT: $OS_ERROR";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( -t STDOUT ) {
|
|
||||||
PTDEBUG && _d('No log file and STDOUT is a terminal;',
|
|
||||||
'redirecting to /dev/null');
|
|
||||||
close STDOUT;
|
close STDOUT;
|
||||||
open STDOUT, '>', '/dev/null'
|
open STDOUT, '>>', $log_file
|
||||||
or die "Cannot reopen STDOUT to /dev/null: $OS_ERROR";
|
or die "Cannot open log file $log_file: $OS_ERROR";
|
||||||
}
|
|
||||||
if ( -t STDERR ) {
|
# If we don't close STDERR explicitly, then prove Daemon.t fails
|
||||||
PTDEBUG && _d('No log file and STDERR is a terminal;',
|
# because STDERR gets written before STDOUT even though we print
|
||||||
'redirecting to /dev/null');
|
# to STDOUT first in the tests. I don't know why, but it's probably
|
||||||
|
# best that we just explicitly close all fds before reopening them.
|
||||||
close STDERR;
|
close STDERR;
|
||||||
open STDERR, '>', '/dev/null'
|
open STDERR, ">&STDOUT"
|
||||||
or die "Cannot reopen STDERR to /dev/null: $OS_ERROR";
|
or die "Cannot dupe STDERR to STDOUT: $OS_ERROR";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( -t STDOUT ) {
|
||||||
|
PTDEBUG && _d('No log file and STDOUT is a terminal;',
|
||||||
|
'redirecting to /dev/null');
|
||||||
|
close STDOUT;
|
||||||
|
open STDOUT, '>', '/dev/null'
|
||||||
|
or die "Cannot reopen STDOUT to /dev/null: $OS_ERROR";
|
||||||
|
}
|
||||||
|
if ( -t STDERR ) {
|
||||||
|
PTDEBUG && _d('No log file and STDERR is a terminal;',
|
||||||
|
'redirecting to /dev/null');
|
||||||
|
close STDERR;
|
||||||
|
open STDERR, '>', '/dev/null'
|
||||||
|
or die "Cannot reopen STDERR to /dev/null: $OS_ERROR";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# XXX: I don't think we need this?
|
PTDEBUG && _d('Daemon running');
|
||||||
# $OUTPUT_AUTOFLUSH = 1;
|
|
||||||
|
|
||||||
PTDEBUG && _d('I am child', $PID);
|
|
||||||
|
|
||||||
# Now update the pid file to contain the correct pid, i.e. the child's pid.
|
|
||||||
if ( $pid_file ) {
|
|
||||||
$self->_update_pid_file(
|
|
||||||
pid => $PID, # child's pid
|
|
||||||
pid_file => $pid_file,
|
|
||||||
);
|
|
||||||
$self->{pid_file_owner} = $PID;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Last: other misc daemon stuff.
|
|
||||||
POSIX::setsid() or die "Cannot start a new session: $OS_ERROR";
|
|
||||||
chdir '/' or die "Cannot chdir to /: $OS_ERROR";
|
|
||||||
|
|
||||||
# We're not fully daemonized.
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Call this for non-daemonized scripts to make a PID file.
|
# Call this for non-daemonized scripts to make a PID file.
|
||||||
sub _make_pid_file {
|
sub _make_pid_file {
|
||||||
my ($self, %args) = @_;
|
my ($self, %args) = @_;
|
||||||
|
Reference in New Issue
Block a user