46
46
croak "mandatory option ``exec'' is missing or is not an arrayref\n"
47
47
unless $opts->{exec} && ref $opts->{exec} eq 'ARRAY';
50
$ENV{ENVDIR} = $opts->{envdir}
51
if defined $opts->{envdir};
52
$ENV{ENABLE_AUTO_RESTART} = $opts->{enable_auto_restart}
53
if defined $opts->{enable_auto_restart};
54
$ENV{KILL_OLD_DELAY} = $opts->{kill_old_delay}
55
if defined $opts->{kill_old_delay};
56
$ENV{AUTO_RESTART_INTERVAL} = $opts->{auto_restart_interval}
57
if defined $opts->{auto_restart_interval};
50
60
my $pid_file_guard = sub {
51
61
return unless $opts->{pid_file};
125
135
or die "failed to remove existing socket file:$path:$!";
138
my $saved_umask = umask(0);
128
139
my $sock = IO::Socket::UNIX->new(
129
140
Listen => Socket::SOMAXCONN(),
131
142
) or die "failed to listen to file $path:$!";
132
144
fcntl($sock, F_SETFD, my $flags = '')
133
145
or die "fcntl(F_SETFD, 0) failed:$!";
134
146
push @sockenv, "$path=" . $sock->fileno;
169
181
$current_worker = _start_worker($opts);
170
182
$update_status->();
183
my $auto_restart_interval = 0;
184
my $last_restart_time = time();
185
my $restart_flag = 0;
172
my @r = wait3(! scalar @signals_received);
174
my ($died_worker, $status) = @r;
188
if ($ENV{ENABLE_AUTO_RESTART}) {
189
# restart workers periodically
190
$auto_restart_interval = $ENV{AUTO_RESTART_INTERVAL} ||= 360;
193
my $died_worker = -1;
196
$died_worker = waitpid(-1, WNOHANG);
198
last if ($died_worker <= 0);
175
199
if ($died_worker == $current_worker) {
176
200
print STDERR "worker $died_worker died unexpectedly with status:$status, restarting\n";
177
201
$current_worker = _start_worker($opts);
202
$last_restart_time = time();
179
204
print STDERR "old worker $died_worker died, status:$status\n";
180
205
delete $old_workers{$died_worker};
206
# don't update the status file if restart is scheduled and died_worker is the last one
207
if ($restart_flag == 0 || scalar(keys %old_workers) != 0) {
212
if ($auto_restart_interval > 0 && scalar(@signals_received) == 0 &&
213
time() > $last_restart_time + $auto_restart_interval) {
214
print STDERR "autorestart triggered (interval=$auto_restart_interval)\n";
216
if (time() > $last_restart_time + $auto_restart_interval * 2) {
217
print STDERR "force autorestart triggered\n";
221
my $num_old_workers = scalar(keys %old_workers);
184
222
for (; @signals_received; shift @signals_received) {
185
223
if ($signals_received[0] eq 'HUP') {
186
print STDERR "received HUP, spawning a new worker\n";
187
$old_workers{$current_worker} = $ENV{SERVER_STARTER_GENERATION};
188
$current_worker = _start_worker($opts);
190
print STDERR "new worker is now running, sending $opts->{signal_on_hup} to old workers:";
192
print STDERR join(',', sort keys %old_workers), "\n";
194
print STDERR "none\n";
196
kill $opts->{signal_on_hup}, $_
197
for sort keys %old_workers;
224
print STDERR "received HUP (num_old_workers=$num_old_workers)\n";
199
227
$term_signal = $signals_received[0] eq 'TERM' ? $opts->{signal_on_term} : 'TERM';
231
if ($restart_flag > 1 || ($restart_flag > 0 && $num_old_workers == 0)) {
232
print STDERR "spawning a new worker (num_old_workers=$num_old_workers)\n";
233
$old_workers{$current_worker} = $ENV{SERVER_STARTER_GENERATION};
234
$current_worker = _start_worker($opts);
235
$last_restart_time = time();
238
print STDERR "new worker is now running, sending $opts->{signal_on_hup} to old workers:";
240
print STDERR join(',', sort keys %old_workers), "\n";
242
print STDERR "none\n";
244
my $kill_old_delay = $ENV{KILL_OLD_DELAY} || 0;
245
$kill_old_delay ||= 5 if $ENV{ENABLE_AUTO_RESTART};
246
print STDERR "sleep $kill_old_delay secs\n";
247
sleep($kill_old_delay) if $kill_old_delay > 0;
248
print STDERR "killing old workers\n";
249
kill $opts->{signal_on_hup}, $_
250
for sort keys %old_workers;