#!/usr/bin/perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/../lib"; use YAML::Syck; use Pod::Usage; use IO::File; use POSIX 'setsid'; use Cwd 'abs_path'; my $conf; BEGIN { $conf = LoadFile('myapp.yml'); $ENV{CATALYST_ENGINE} = $conf->{catalyst_engine}; } use constant PID_FILE => "/var/tmp/$conf->{name}.pid"; my @argv = @ARGV; my $command = shift; if ($command =~ /^help\z/i) { pod2usage(-exitval => 0, -verbose => 2) } elsif ($command =~ /^start\z/i) { start() } elsif ($command =~ /^stop\z/i) { stop() } elsif ($command =~ /^restart\z/i) { stop(); start() } else { pod2usage(1) } sub stop { my $pid = eval { IO::File->new(PID_FILE)->getline }; if ($pid) { # I don't know why I have to do this, but it doesn't work otherwise. kill INT => $pid; sleep 1; kill INT => $pid; } else { print STDERR "Not running.\n"; exit 1; } } sub start { # Set up logging. (my $log_dir = $conf->{log_dir}) =~ s/~/$ENV{HOME}/; my $log_pipe = abs_path('bin/rotatelogs') . " $log_dir/$conf->{rotatelogs_format}"; # Log and display initial output. open STDERR, "| tee /dev/tty | $log_pipe" or die "Can't pipe to bin/rotatelogs: $!"; require Catalyst::Engine::HTTP; require "$conf->{name}.pm"; daemonize(); $0 = $conf->{name}; require Proc::PID::File; print(STDERR "Already running.\n"), exit if Proc::PID::File->running(dir => '/var/tmp', verify => 1); close STDERR; open STDERR, "|$log_pipe" or die "Can't pipe to bin/rotatelogs: $!"; STDERR->autoflush(1); open STDOUT, '>/dev/null' or die "Can’t write to /dev/null: $!"; open STDIN, '/dev/null' or die "Can’t read /dev/null: $!"; $SIG{INT} = sub { unlink PID_FILE }; $SIG{TERM} = sub { kill INT => $$ }; LPS->run($conf->{port}, $conf->{host}, { argv => \@argv, keepalive => $conf->{keepalive}, max_proc => $ENV{CATALYST_POE_MAX_PROC} || $conf->{poe_max_proc} || 6 }); unlink PID_FILE; } # adapted from perlipc sub daemonize { chdir '/' or die "Can’t chdir to /: $!"; # fork twice to fully detach for (0..1) { defined(my $pid = fork) or die "Can’t fork: $!"; exit if $pid; } setsid or die "Can’t start a new session: $!"; } =head1 NAME myappctl - Start and stop your POE-backed Catalyst server =head1 SYNOPSIS lpsctl [command] Options: start start the server stop stop the server restart restart the server help display documentation =head1 DESCRIPTION Run the Catalyst Server using the POE backend. Sample configuration (this goes into myapp.yml): name: MyApp catalyst_engine: 'HTTP::POE' poe_max_proc: 6 # Leave host unset to bind to all available interfaces. # host: localhost port: 3000 keepalive: 1 log_dir: '~/logs/myapp' # Put a link or copy of Apache's rotatelogs into MyApp/bin. # See man rotatelogs for details about the format. rotatelogs_format: 'myapp_ui_log.%Y-%m-%d-%H 3600 -480' =head1 AUTHOR Rafael Kitover C =head1 COPYRIGHT This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut