-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathStart.PL
executable file
·140 lines (115 loc) · 3.51 KB
/
Start.PL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/env perl
use strict;
use warnings;
use JSON::XS;
use Getopt::Long;
use POSIX qw(setsid);
use IO::Socket::INET;
use Time::HiRes qw(sleep);
use FindBin qw($Bin);
use lib "$Bin/lib", "$Bin/local/lib";
use App::Its::Potracheno::Config;
my $root = "$Bin";
my $config_file = "$root/local/potracheno.cfg";
my $app = "$root/bin/potracheno.psgi";
# getopt here?
my $conf = App::Its::Potracheno::Config->load_config(
$config_file, ROOT => $root );
$conf = $conf->{server};
$conf->{port} ||= 5000;
$conf->{access_log} ||= "$root/local/access.log";
$conf->{error_log} ||= "$root/local/error.log";
$conf->{pidfile} ||= "$root/local/pid.txt";
my $server = $conf->{server} || "plackup";
my $action = shift;
if (!$action) {
print "Usage: perl $0 [start|stop|restart]\n";
exit 0;
};
if ($action eq 'restart' || $action eq 'start') {
stop() && start();
} elsif ($action eq 'stop' ) {
stop();
} else {
die "Unknown action $action";
};
sub start {
print "Checking $app...\n";
open my $pipe, "-|", perl => $app;
local $/;
my $content = <$pipe>;
$content =~ /<body>/ or die "Unable to start $app";
print "Running server...\n";
my $pid;
local $SIG{CHLD} = sub { die "Premature exit from child ($pid)" };
$pid = fork;
die "Fork failed: $!" unless defined $pid;
if (!$pid) {
# CHILD SECTION
setsid();
open STDIN, "<", "/dev/null"
or die "Failed to redirect STDIN: $!";
open STDOUT, ">>", $conf->{error_log}
or die "Failed to redirect STDOUT: $!";
open STDERR, ">>", $conf->{error_log}
or die "Failed to redirect STDERR: $!";
exec $server => '--listen' => ":$conf->{port}"
=> '--access-log' => $conf->{access_log}
=> $app
or die "Exec failed: $!";
# END CHILD SECTION
};
open my $fd, ">", $conf->{pidfile}
or die "Failed to save pid $pid to file $conf->{pidfile}: $!";
print $fd $pid
or die "Failed to save pid $pid to file $conf->{pidfile}: $!";
close $fd
or die "Failed to save pid $pid to file $conf->{pidfile}: $!";
print "Waiting for port $conf->{port}...\n";
wait_for_port( $conf->{port}, 1 );
undef $SIG{CHLD};
print "Start OK\n";
return 1;
};
sub stop {
# No pidfile = ok
-f $conf->{pidfile} or return 1;
open (my $fd, "<", $conf->{pidfile})
or die "Failed to read pidfile $conf->{pidfile}: $!";
my $pid = <$fd>;
chomp $pid;
die "Broken pid file $conf->{pidfile}"
unless $pid =~ /^\d+$/;
# detect stale pid
if ([stat $fd]->[9] >= ([stat "/proc/$pid/fd/0"]->[9] || 9**9**9)) {
print "Killing pid $pid...\n";
kill INT => $pid
or die "Failed to send signal: $!";
} else {
warn "Stale pid detected in $conf->{pidfile}: $pid";
};
print "Waiting for port $conf->{port}...\n";
wait_for_port( $conf->{port}, 0 );
unlink $conf->{pidfile};
print "Stop OK\n";
return 1;
};
sub wait_for_port {
my ($port, $on_off) = @_;
local $SIG{ALRM} = sub { die "Failed to wait for socket to "
.($on_off ? "start" : "stop") };
alarm 10;
my $int = 0.01;
while ( 1 ) {
my $sock = IO::Socket::INET->new(
Proto => "tcp",
PeerHost => "localhost",
PeerPort => $port,
);
close $sock if $sock;
last unless $sock xor $on_off; # sock and on_off must be both true | both false
sleep $int;
$int *= 1.3;
};
alarm 0;
};