Skip to content

Commit

Permalink
improved Hypnotoad with many info level log messages
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Feb 24, 2012
1 parent 5c80238 commit 864bb29
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 42 deletions.
1 change: 1 addition & 0 deletions Changes
@@ -1,6 +1,7 @@
This file documents the revision history for Perl extension Mojolicious.

2.53 2012-02-25 00:00:00
- Improved Hypnotoad with many info level log messages.
- Improved documentation.

2.52 2012-02-24 00:00:00
Expand Down
69 changes: 27 additions & 42 deletions lib/Mojo/Server/Hypnotoad.pm
Expand Up @@ -17,8 +17,6 @@ use Time::HiRes 'ualarm';
# Preload
use Mojo::UserAgent;

use constant DEBUG => $ENV{HYPNOTOAD_DEBUG} || 0;

sub DESTROY {
my $self = shift;

Expand All @@ -45,13 +43,13 @@ sub DESTROY {
# Uhhh, dad, Lisa's the one you're not talking to.
# Bart, go to your room."
sub run {
my ($self, $app, $config) = @_;
my ($self, $path, $config) = @_;

# No windows support
_exit('Hypnotoad not available for Windows.') if $^O eq 'MSWin32';

# Application
$ENV{HYPNOTOAD_APP} ||= abs_path $app;
$ENV{HYPNOTOAD_APP} ||= abs_path $path;

# DEPRECATED in Leaf Fluttering In Wind!
$ENV{HYPNOTOAD_CONFIG} ||= abs_path $config;
Expand All @@ -68,8 +66,8 @@ sub run {

# Preload application and configure server
my $daemon = $self->{daemon} = Mojo::Server::Daemon->new;
warn "APPLICATION $ENV{HYPNOTOAD_APP}\n" if DEBUG;
$self->_config($daemon->load_app($ENV{HYPNOTOAD_APP}));
$self->_config(my $app = $daemon->load_app($ENV{HYPNOTOAD_APP}));
(my $log = $app->log)->info(qq/Loading application "$ENV{HYPNOTOAD_APP}"./);

# Testing
_exit('Everything looks good!') if $ENV{HYPNOTOAD_TEST};
Expand All @@ -81,7 +79,7 @@ sub run {
$self->_hot_deploy unless $ENV{HYPNOTOAD_PID};

# Daemonize as early as possible
if (!DEBUG && !$ENV{HYPNOTOAD_FOREGROUND}) {
unless ($ENV{HYPNOTOAD_FOREGROUND}) {

# Fork and kill parent
die "Can't fork: $!" unless defined(my $pid = fork);
Expand All @@ -107,7 +105,7 @@ sub run {
my $c = $self->{config};
$SIG{INT} = $SIG{TERM} = sub { $self->{finished} = 1 };
$SIG{CHLD} = sub {
while ((my $pid = waitpid -1, WNOHANG) > 0) { $self->_reap($pid) }
while ((my $pid = waitpid -1, WNOHANG) > 0) { $self->_reap($log, $pid) }
};
$SIG{QUIT} = sub { $self->{finished} = $self->{graceful} = 1 };
$SIG{USR2} = sub { $self->{upgrade} ||= time };
Expand All @@ -119,8 +117,8 @@ sub run {
};

# Mainloop
warn "MANAGER STARTED $$\n" if DEBUG;
$self->_manage while 1;
$log->info("Manager $$ started.");
$self->_manage($log) while 1;
}

sub _config {
Expand All @@ -130,9 +128,7 @@ sub _config {
my $c = $app->config('hypnotoad') || {};

# DEPRECATED in Leaf Fluttering In Wind!
my $file = $ENV{HYPNOTOAD_CONFIG};
warn "CONFIG $file\n" if DEBUG;
if (-r $file) {
if (-r (my $file = $ENV{HYPNOTOAD_CONFIG})) {
warn "Hypnotoad config files are DEPRECATED!\n";
unless ($c = do $file) {
die qq/Can't load config file "$file": $@/ if $@;
Expand Down Expand Up @@ -205,25 +201,25 @@ sub _hot_deploy {
}

sub _manage {
my $self = shift;
my ($self, $log) = @_;

# Housekeeping
my $c = $self->{config};
if (!$self->{finished}) {

# Spawn more workers
$self->_spawn while keys %{$self->{workers}} < $c->{workers};
$self->_spawn($log) while keys %{$self->{workers}} < $c->{workers};

# Check PID file
$self->_pid_file;
$self->_pid_file($log);
}

# Shutdown
elsif (!keys %{$self->{workers}}) { exit 0 }

# Upgraded
if ($ENV{HYPNOTOAD_PID} && $ENV{HYPNOTOAD_PID} ne $$) {
warn "STOPPING MANAGER $ENV{HYPNOTOAD_PID}\n" if DEBUG;
$log->info("Stopping manager $ENV{HYPNOTOAD_PID}.");
kill 'QUIT', $ENV{HYPNOTOAD_PID};
}
$ENV{HYPNOTOAD_PID} = $$;
Expand All @@ -236,7 +232,7 @@ sub _manage {

# Fresh start
unless ($self->{new}) {
warn "UPGRADING\n" if DEBUG;
$log->info('Starting zero downtime software upgrade.');
croak "Can't fork: $!" unless defined(my $pid = fork);
$self->{new} = $pid if $pid;
exec $ENV{HYPNOTOAD_EXE} unless $pid;
Expand All @@ -250,32 +246,29 @@ sub _manage {
# Workers
while (my ($pid, $w) = each %{$self->{workers}}) {

# No heartbeat
# No heartbeat (graceful stop)
my $interval = $c->{heartbeat_interval};
my $timeout = $c->{heartbeat_timeout};
if ($w->{time} + $interval + $timeout <= time) {

# Try graceful
warn "STOPPING WORKER $pid\n" if DEBUG;
$log->info("Worker $pid has no heartbeat.");
$w->{graceful} ||= time;
}

# Graceful stop
$w->{graceful} ||= time if $self->{graceful};
if ($w->{graceful}) {
warn "QUIT $pid\n" if DEBUG;
$log->info("Trying to stop worker $pid gracefully.");
kill 'QUIT', $pid;

# Timeout
$w->{force} = 1
if $w->{graceful} + $c->{graceful_timeout} <= time;
$w->{force} = 1 if $w->{graceful} + $c->{graceful_timeout} <= time;
}

# Normal stop
if (($self->{finished} && !$self->{graceful}) || $w->{force}) {

# Kill
warn "KILL $pid\n" if DEBUG;
$log->info("Stopping worker $pid.");
kill 'KILL', $pid;
}
}
Expand All @@ -290,17 +283,16 @@ sub _pid {
}

sub _pid_file {
my $self = shift;
my ($self, $log) = @_;

# Don't need a PID file anymore
return if $self->{finished};

# Check if PID file already exists
my $file = $self->{config}->{pid_file};
return if -e $file;
return if -e (my $file = $self->{config}->{pid_file});

# Create PID file
warn "PID $file\n" if DEBUG;
$log->info(qq/Creating PID file "$file" for manager $$./);
croak qq/Can't create PID file "$file": $!/
unless my $pid = IO::File->new($file, '>', 0644);
print $pid $$;
Expand All @@ -310,25 +302,25 @@ sub _pid_file {
# Please eliminate three.
# P.S. I am not a crackpot."
sub _reap {
my ($self, $pid) = @_;
my ($self, $log, $pid) = @_;

# Clean up failed upgrade
if (($self->{new} || '') eq $pid) {
warn "UPGRADE FAILED\n" if DEBUG;
$log->info('Zero downtime software upgrade failed.');
delete $self->{upgrade};
delete $self->{new};
}

# Clean up worker
else {
warn "WORKER DIED $pid\n" if DEBUG;
$log->info("Worker $pid stopped.");
delete $self->{workers}->{$pid};
}
}

# "I hope this has taught you kids a lesson: kids never learn."
sub _spawn {
my $self = shift;
my ($self, $log) = @_;

# Fork
croak "Can't fork: $!" unless defined(my $pid = fork);
Expand Down Expand Up @@ -391,7 +383,7 @@ sub _spawn {
$daemon->setuidgid;

# Start
warn "WORKER STARTED $$\n" if DEBUG;
$log->info("Worker $$ started.");
$loop->start;
exit 0;
}
Expand Down Expand Up @@ -642,13 +634,6 @@ implements the following new ones.
Run server.
=head1 DEBUGGING
You can set the C<HYPNOTOAD_DEBUG> environment variable to get some advanced
diagnostics information printed to C<STDERR>.
HYPNOTOAD_DEBUG=1
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
Expand Down

0 comments on commit 864bb29

Please sign in to comment.