Skip to content

Commit

Permalink
added daemonize method to Mojo::Server and ensure_pid_file method to …
Browse files Browse the repository at this point in the history
…Mojo::Server::Prefork
  • Loading branch information
kraih committed Mar 28, 2014
1 parent 32e4a7a commit 821844b
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 79 deletions.
4 changes: 3 additions & 1 deletion Changes
@@ -1,5 +1,7 @@

4.91 2014-03-27
4.91 2014-03-29
- Added daemonize method to Mojo::Server.
- Added ensure_pid_file method to Mojo::Server::Prefork.
- Removed deprecated secret method from Mojolicious.
- Improved performance of Mojolicious::Plugin::EPRenderer and
Mojolicious::Plugin::EPLRenderer.
Expand Down
64 changes: 64 additions & 0 deletions lib/Mojo/Server.pm
Expand Up @@ -4,9 +4,11 @@ use Mojo::Base 'Mojo::EventEmitter';
use Carp 'croak';
use Mojo::Loader;
use Mojo::Util 'md5_sum';
use POSIX;
use Scalar::Util 'blessed';

has app => sub { shift->build_app('Mojo::HelloWorld') };
has [qw(group user)];

sub build_app {
my ($self, $app) = @_;
Expand All @@ -17,6 +19,19 @@ sub build_app {

sub build_tx { shift->app->build_tx }

sub daemonize {

# Fork and kill parent
die "Can't fork: $!" unless defined(my $pid = fork);
exit 0 if $pid;
POSIX::setsid or die "Can't start a new session: $!";

# Close filehandles
open STDIN, '</dev/null';
open STDOUT, '>/dev/null';
open STDERR, '>&STDOUT';
}

sub load_app {
my ($self, $path) = @_;

Expand Down Expand Up @@ -53,6 +68,29 @@ sub new {

sub run { croak 'Method "run" not implemented by subclass' }

sub setuidgid {
my $self = shift;

# Group
if (my $group = $self->group) {
return $self->_log(error => qq{Group "$group" does not exist.})
unless defined(my $gid = getgrnam $group);
return $self->_log(error => qq{Can't switch to group "$group": $!})
unless POSIX::setgid($gid);
}

# User
return $self unless my $user = $self->user;
return $self->_log(error => qq{User "$user" does not exist.})
unless defined(my $uid = getpwnam $user);
return $self->_log(error => qq{Can't switch to user "$user": $!})
unless POSIX::setuid($uid);

return $self;
}

sub _log { $_[0]->app->log->log(@_[1, 2]) and return $_[0] }

1;

=encoding utf8
Expand Down Expand Up @@ -114,6 +152,20 @@ L<Mojo::Server> implements the following attributes.
Application this server handles, defaults to a L<Mojo::HelloWorld> object.
=head2 group
my $group = $server->group;
$server = $server->group('users');
Group for server process.
=head2 user
my $user = $server->user;
$server = $server->user('web');
User for the server process.
=head1 METHODS
L<Mojo::Server> inherits all methods from L<Mojo::EventEmitter> and implements
Expand All @@ -131,6 +183,12 @@ Build application from class.
Let application build a transaction.
=head2 daemonize
$server->daemonize;
Daemonize server process.
=head2 load_app
my $app = $server->load_app('/home/sri/myapp.pl');
Expand All @@ -152,6 +210,12 @@ with default request handling.
Run server. Meant to be overloaded in a subclass.
=head2 setuidgid
$server = $server->setuidgid;
Set L</"user"> and L</"group"> for process.
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
Expand Down
54 changes: 5 additions & 49 deletions lib/Mojo/Server/Daemon.pm
Expand Up @@ -3,13 +3,12 @@ use Mojo::Base 'Mojo::Server';

use Mojo::IOLoop;
use Mojo::URL;
use POSIX;
use Scalar::Util 'weaken';

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

has acceptors => sub { [] };
has [qw(backlog group silent user)];
has [qw(backlog silent)];
has inactivity_timeout => sub { $ENV{MOJO_INACTIVITY_TIMEOUT} // 15 };
has ioloop => sub { Mojo::IOLoop->singleton };
has listen => sub { [split ',', $ENV{MOJO_LISTEN} || 'http://*:3000'] };
Expand All @@ -29,27 +28,6 @@ sub run {
$self->start->setuidgid->ioloop->start;
}

sub setuidgid {
my $self = shift;

# Group
if (my $group = $self->group) {
return $self->_log(error => qq{Group "$group" does not exist.})
unless defined(my $gid = getgrnam $group);
return $self->_log(error => qq{Can't switch to group "$group": $!})
unless POSIX::setgid($gid);
}

# User
return $self unless my $user = $self->user;
return $self->_log(error => qq{User "$user" does not exist.})
unless defined(my $uid = getpwnam $user);
return $self->_log(error => qq{Can't switch to user "$user": $!})
unless POSIX::setuid($uid);

return $self;
}

sub start {
my $self = shift;

Expand Down Expand Up @@ -184,23 +162,21 @@ sub _listen {
$stream->timeout($self->inactivity_timeout);

$stream->on(close => sub { $self->_close($id) });
$stream->on(
error => sub { $self && $self->_log(error => pop)->_close($id) });
$stream->on(error =>
sub { $self && $self->app->log->error(pop) && $self->_close($id) });
$stream->on(read => sub { $self->_read($id => pop) });
$stream->on(timeout =>
sub { $self->_log(debug => 'Inactivity timeout.') if $c->{tx} });
sub { $self->app->log->debug('Inactivity timeout.') if $c->{tx} });
}
);

return if $self->silent;
$self->_log(info => qq{Listening at "$url".});
$self->app->log->info(qq{Listening at "$url".});
$query->params([]);
$url->host('127.0.0.1') if $url->host eq '*';
say "Server available at $url.";
}

sub _log { $_[0]->app->log->log(@_[1, 2]) and return $_[0] }

sub _read {
my ($self, $id, $chunk) = @_;

Expand Down Expand Up @@ -324,13 +300,6 @@ Active acceptors.
Listen backlog size, defaults to C<SOMAXCONN>.
=head2 group
my $group = $daemon->group;
$daemon = $daemon->group('users');
Group for server process.
=head2 inactivity_timeout
my $timeout = $daemon->inactivity_timeout;
Expand Down Expand Up @@ -447,13 +416,6 @@ Maximum number of keep-alive requests per connection, defaults to C<25>.
Disable console messages.
=head2 user
my $user = $daemon->user;
$daemon = $daemon->user('web');
User for the server process.
=head1 METHODS
L<Mojo::Server::Daemon> inherits all methods from L<Mojo::Server> and
Expand All @@ -465,12 +427,6 @@ implements the following new ones.
Run server.
=head2 setuidgid
$daemon = $daemon->setuidgid;
Set user and group for process.
=head2 start
$daemon = $daemon->start;
Expand Down
15 changes: 2 additions & 13 deletions lib/Mojo/Server/Hypnotoad.pm
Expand Up @@ -8,7 +8,6 @@ use File::Basename 'dirname';
use File::Spec::Functions 'catfile';
use Mojo::Server::Prefork;
use Mojo::Util 'steady_time';
use POSIX 'setsid';
use Scalar::Util 'weaken';

sub run {
Expand Down Expand Up @@ -49,18 +48,8 @@ sub run {
$self->_hot_deploy unless $ENV{HYPNOTOAD_PID};

# Daemonize as early as possible (but not for restarts)
if (!$ENV{HYPNOTOAD_FOREGROUND} && $ENV{HYPNOTOAD_REV} < 3) {

# Fork and kill parent
die "Can't fork: $!" unless defined(my $pid = fork);
exit 0 if $pid;
setsid or die "Can't start a new session: $!";

# Close filehandles
open STDIN, '</dev/null';
open STDOUT, '>/dev/null';
open STDERR, '>&STDOUT';
}
$prefork->daemonize
if !$ENV{HYPNOTOAD_FOREGROUND} && $ENV{HYPNOTOAD_REV} < 3;

# Start accepting connections
local $SIG{USR2} = sub { $self->{upgrade} ||= steady_time };
Expand Down
36 changes: 21 additions & 15 deletions lib/Mojo/Server/Prefork.pm
Expand Up @@ -45,6 +45,20 @@ sub check_pid {
return undef;
}

sub ensure_pid_file {
my $self = shift;

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

# Create PID file
$self->app->log->info(qq{Creating process id file "$file".});
die qq{Can't create process id file "$file": $!}
unless open my $handle, '>', $file;
chmod 0644, $handle;
print $handle $$;
}

sub run {
my $self = shift;

Expand Down Expand Up @@ -104,7 +118,7 @@ sub _manage {
# Spawn more workers and check PID file
if (!$self->{finished}) {
$self->_spawn while keys %{$self->{pool}} < $self->workers;
$self->_pid_file;
$self->ensure_pid_file;
}

# Shutdown
Expand Down Expand Up @@ -141,20 +155,6 @@ sub _manage {
}
}

sub _pid_file {
my $self = shift;

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

# Create PID file
$self->app->log->info(qq{Creating process id file "$file".});
die qq{Can't create process id file "$file": $!}
unless open my $handle, '>', $file;
chmod 0644, $handle;
print $handle $$;
}

sub _spawn {
my $self = shift;

Expand Down Expand Up @@ -482,6 +482,12 @@ is not running.
say 'Server is not running' unless $prefork->check_pid;
=head2 ensure_pid_file
$prefork->ensure_pid_file;
Ensure L</"pid_file"> exists.
=head2 run
$prefork->run;
Expand Down
5 changes: 4 additions & 1 deletion t/mojo/prefork.t
Expand Up @@ -15,10 +15,13 @@ use Mojo::Server::Prefork;
use Mojo::UserAgent;
use Mojo::Util 'spurt';

# Clean up PID file
# Manage and clean up PID file
my $prefork = Mojo::Server::Prefork->new;
my $file = $prefork->pid_file;
ok !$prefork->check_pid, 'no process id';
$prefork->ensure_pid_file;
ok -e $file, 'file exists';
is $prefork->check_pid, $$, 'right process id';
spurt "\n", $file;
ok -e $file, 'file exists';
ok !$prefork->check_pid, 'no process id';
Expand Down

0 comments on commit 821844b

Please sign in to comment.