Permalink
Browse files

Merge branch 'master' of github.com:berekuk/Ubic

  • Loading branch information...
2 parents 7bfa0c5 + c28eaa3 commit d98369d70f9b2f16011b244c80b50a1d9aaef472 @berekuk committed Apr 13, 2012
Showing with 93 additions and 50 deletions.
  1. +3 −0 Changes
  2. +7 −6 README.md
  3. +3 −3 debian/control
  4. +1 −1 dist.ini
  5. +54 −37 lib/Ubic/Daemon.pm
  6. +25 −3 t/daemon.t
View
3 Changes
@@ -2,6 +2,9 @@ Revision history for Ubic
{{$NEXT}}
+1.37_03 2012-04-13
+ * log early exiting daemons correctly; fix tests
+
1.37_02 2012-03-28
* non-root dir multiservices allow operations without --force
* minor docs improvements, including replacing "flexible perl-based" with "polymorphic" everywhere
View
13 README.md
@@ -2,14 +2,15 @@
Ubic is a polymorphic service manager.
+"Polymorphic" means that Ubic can use various pluggable backends for managing services, for configuring services and even for describing a list of all services.
+Don't panic, it offers easy-to-use default solutions for the common tasks out-of-the-box too!
+
## 1 minute intro
-Put this code in file `/etc/ubic/service/example`:
+Put this code in file `/etc/ubic/service/example.ini`:
- use Ubic::Service::SimpleDaemon;
- Ubic::Service::SimpleDaemon->new(
- bin => 'sleep 1000',
- );
+ [options]
+ bin = sleep 100
Start it:
@@ -77,7 +78,7 @@ There is also a low-volume mailing list is <ubic-perl@googlegroups.com>. Send an
## Copyright and licence
-Copyright (c) 2009-2011 Yandex LTD. All rights reserved.
+Copyright (c) 2009-2012 Yandex LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
View
6 debian/control
@@ -16,7 +16,7 @@ Depends: ${perl:Depends},
Provides: yandex-ubic
Replaces: yandex-ubic (<< 1.00)
Conflicts: yandex-ubic (<< 1.00)
-Description: flexible perl-based service manager
+Description: polymorphic service manager
Each ubic service is represented by perl object, so code reuse is trivial.
- Watchdog, neat color output and SysV-style LSB conformant init scripts are
- supported.
+ Watchdog, neat color output and SysV-style LSB conformant init scripts support
+ is included.
View
2 dist.ini
@@ -1,5 +1,5 @@
name = Ubic
-version = 1.37_02
+version = 1.37_03
author = Vyacheslav Matyukhin <mmcleric@yandex-team.ru>
license = Perl_5
copyright_holder = Yandex LLC
View
91 lib/Ubic/Daemon.pm
@@ -28,7 +28,7 @@ so if you need to get daemon's pid, don't try to read pidfile directly, use C<ch
=cut
use IO::Handle;
-use POSIX qw(setsid);
+use POSIX qw(setsid :sys_wait_h);
use Time::HiRes qw(sleep);
use Params::Validate qw(:all);
use Carp;
@@ -79,6 +79,32 @@ sub _log {
print {$fh} '[', scalar(localtime), "]\t$$\t", @_, "\n";
}
+sub _log_exit_code {
+ my ($fh, $code, $pid) = @_;
+ if ($code == 0) {
+ _log($fh, "daemon $pid exited");
+ return;
+ }
+
+ my $msg = "daemon $pid failed with \$? = $?";
+ if (my $signal = $? & 127) {
+ my $signame = _signame($signal);
+ if (defined $signame) {
+ $msg = "daemon $pid failed with signal $signame ($signal)";
+ }
+ else {
+ $msg = "daemon $pid failed with signal $signal";
+ }
+ }
+ elsif ($? & 128) {
+ $msg = "daemon $pid failed, core dumped";
+ }
+ elsif (my $code = $? >> 8) {
+ $msg = "daemon $pid failed, exit code $code";
+ }
+ _log($fh, $msg);
+}
+
=item B<stop_daemon($pidfile)>
=item B<stop_daemon($pidfile, $options)>
@@ -263,12 +289,11 @@ sub start_daemon($) {
my $ubic_fh;
my $lock;
my $instant_exit = sub {
- my $status = shift; # nobody cares for this status anyway...
close($ubic_fh) if $ubic_fh;
STDOUT->flush;
STDERR->flush;
undef $lock;
- POSIX::_exit($status); # don't allow any cleanup to happen - this process was forked from unknown environment, don't want to run unknown destructors
+ POSIX::_exit(0); # don't allow any cleanup to happen - this process was forked from unknown environment, don't want to run unknown destructors
};
eval {
@@ -325,14 +350,25 @@ sub start_daemon($) {
if ($child = fork) {
# guardian
+ _log($ubic_fh, "guardian pid: $$");
+ _log($ubic_fh, "daemon pid: $child");
+
my $child_guid = $OS->pid2guid($child);
- die "Can't detect guid" unless $child_guid;
+ unless ($child_guid) {
+ if ($OS->pid_exists($child)) {
+ die "Can't detect guid";
+ }
+ $? = 0;
+ unless (waitpid($child, WNOHANG) == $child) {
+ die "No pid $child but waitpid didn't collect $child status";
+ }
+ _log_exit_code($ubic_fh, $?, $child);
+ $pid_state->remove();
+ die "daemon exited immediately";
+ }
_log($ubic_fh, "child guid: $child_guid");
$pid_state->write({ pid => $child, guid => $child_guid });
- _log($ubic_fh, "guardian pid: $$");
- _log($ubic_fh, "daemon pid: $child");
-
my $kill_sub = sub {
if ($term_timeout) {
_log($ubic_fh, "SIGTERM timeouted after $term_timeout second(s)");
@@ -341,7 +377,7 @@ sub start_daemon($) {
kill -9 => $child;
_log($ubic_fh, "daemon $child probably killed by SIGKILL");
$pid_state->remove();
- $instant_exit->(0);
+ $instant_exit->();
};
my $sigterm_sent;
@@ -359,39 +395,19 @@ sub start_daemon($) {
};
print {$write_pipe} "pidfile written\n" or die "Can't write to pipe: $!";
close $write_pipe or die "Can't close pipe: $!";
+ undef $write_pipe;
$? = 0;
waitpid($child, 0);
- if ($? > 0) {
- my $msg = "daemon $child failed with \$? = $?";
- if (my $signal = $? & 127) {
- if ($sigterm_sent && $signal == &POSIX::SIGTERM) {
- # it's ok, we probably sent this signal ourselves
- _log($ubic_fh, "daemon $child exited by sigterm");
- $pid_state->remove;
- $instant_exit->(0);
- }
- my $signame = _signame($signal);
- if (defined $signame) {
- $msg = "daemon $child failed with signal $signame ($signal)";
- }
- else {
- $msg = "daemon $child failed with signal $signal";
- }
- }
- elsif ($? & 128) {
- $msg = "daemon $child failed, core dumped";
- }
- elsif (my $code = $? >> 8) {
- $msg = "daemon $child failed, exit code $code";
- }
- _log($ubic_fh, $msg);
- $pid_state->remove;
- $instant_exit->(1);
+ my $code = $?;
+ if ($sigterm_sent and ($code & 127) == &POSIX::SIGTERM) {
+ # it's ok, we probably sent this signal ourselves
+ _log($ubic_fh, "daemon $child exited by sigterm");
+ }
+ else {
+ _log_exit_code($ubic_fh, $code, $child);
}
- _log($ubic_fh, "daemon $child exited");
$pid_state->remove;
- $instant_exit->(0);
}
else {
# daemon
@@ -414,6 +430,7 @@ sub start_daemon($) {
print {$write_pipe} "execing into daemon\n" or die "Can't write to pipe: $!";
close($write_pipe) or die "Can't close pipe: $!";
+ undef $write_pipe;
# finally, run underlying binary
if (ref $bin) {
@@ -431,7 +448,7 @@ sub start_daemon($) {
print {$write_pipe} "Error: $@\n";
$write_pipe->flush;
}
- $instant_exit->(1);
+ $instant_exit->();
}
waitpid($child, 0); # child should've exited immediately
close($write_pipe) or die "Can't close write_pipe: $!";
View
28 t/daemon.t
@@ -3,7 +3,7 @@
use strict;
use warnings;
-use Test::More tests => 28;
+use Test::More tests => 29;
use Test::Exception;
use lib 'lib';
@@ -271,17 +271,39 @@ qr{\QError: Can't write to 'tfiles/non-existent/forbidden.log'\E},
{
rebuild_tfiles; local_ubic;
start_daemon({
- bin => ['perl', '-e', 'exit 3'],
+ bin => ['perl', '-e', 'sleep 1; exit 3'],
pidfile => "tfiles/pid",
ubic_log => 'tfiles/ubic.log',
});
- sleep 1;
+ sleep 2;
my $log = slurp('tfiles/ubic.log');
like($log, qr/daemon \d+ failed, exit code 3$/m, 'exit with non-zero code');
}
{
rebuild_tfiles; local_ubic;
+ # there are two options:
+ # 1) daemon exits before ubic-guardian finishes its initialization; in this case, start_daemon will throw an exception
+ # 2) ubic-guardian finishes its initialization and then daemon exits; in this case, we check for ubic.log
+ eval {
+ start_daemon({
+ bin => ['perl', '-e', 'exit 3'],
+ pidfile => "tfiles/pid",
+ ubic_log => 'tfiles/ubic.log',
+ });
+ };
+ if ($@) {
+ like($@, qr/daemon exited immediately/, 'daemon exits immediately, before guardian initialization');
+ }
+ else {
+ sleep 1;
+ my $log = slurp('tfiles/ubic.log');
+ like($log, qr/daemon \d+ failed, exit code 3$/m, 'daemon exits immediately, after guardian initialization');
+ }
+ }
+
+ {
+ rebuild_tfiles; local_ubic;
start_daemon({
bin => ['perl', '-e', '$SIG{TERM} = "IGNORE"; sleep 30'],
pidfile => "tfiles/pid",

0 comments on commit d98369d

Please sign in to comment.