File Coverage

blib/lib/Plack/Handler/Starlet.pm
Criterion Covered Total %
statement 66 72 91.6
branch 22 30 73.3
condition n/a
subroutine 8 9 88.8
pod 0 2 0.0
total 96 113 84.9


line stmt bran cond sub pod time code
1             package Plack::Handler::Starlet;
2              
3 112     112   115362745 use strict;
  112         539  
  112         6707  
4 112     112   1161 use warnings;
  112         356  
  112         9009  
5              
6 112     112   59792 use Parallel::Prefork;
  112         507811  
  112         2199  
7 112     112   54911 use Server::Starter ();
  112         735783  
  112         2880  
8 112     112   720 use base qw(Starlet::Server);
  112         190  
  112         54926  
9              
10             sub new {
11 112     112 0 4955 my ($klass, %args) = @_;
12            
13             # setup before instantiation
14 112 100       836 if (defined $ENV{SERVER_STARTER_PORT}) {
15 9         12 $args{listens} = [];
16 9         33 my $server_ports = Server::Starter::server_ports();
17 9         135 for my $hostport (keys %$server_ports) {
18 27         33 my $fd = $server_ports->{$hostport};
19 27         33 my $listen = {};
20 27 50       66 if ($hostport =~ /(.*):(\d+)/) {
21 0         0 $listen->{host} = $1;
22 0         0 $listen->{port} = $2;
23             } else {
24 27         36 $listen->{port} = $hostport;
25             }
26 27 50       165 $listen->{sock} = IO::Socket::INET->new(
27             Proto => 'tcp',
28             ) or die "failed to create socket:$!";
29 27 50       4137 $listen->{sock}->fdopen($fd, 'w')
30             or die "failed to bind to listening socket:$!";
31 27 100       1038 unless (@{$args{listens}}) {
  27         72  
32 9         12 $args{host} = $listen->{host};
33 9         15 $args{port} = $listen->{port};
34             }
35 27         81 $args{listens}[$fd] = $listen;
36             }
37             }
38 112         151 my $max_workers = 10;
39 112         258 for (qw(max_workers workers)) {
40             $max_workers = delete $args{$_}
41 224 100       698 if defined $args{$_};
42             }
43            
44 112 100       746 if ($args{child_exit}) {
45 2 50       104 $args{child_exit} = eval $args{child_exit} unless ref($args{child_exit});
46 2 50       6 die "child_exit is defined but not a code block" if ref($args{child_exit}) ne 'CODE';
47             }
48            
49             # instantiate and set the variables
50 112         777 my $self = $klass->SUPER::new(%args);
51 112         561 $self->{is_multiprocess} = 1;
52 112         296 $self->{max_workers} = $max_workers;
53            
54 112         685 $self;
55             }
56              
57             sub run {
58 111     111 0 3686 my($self, $app) = @_;
59 111         718 $self->setup_listener();
60 111 100       584 if ($self->{max_workers} != 0) {
61             # use Parallel::Prefork
62             my %pm_args = (
63             max_workers => $self->{max_workers},
64 110         439 trap_signals => {
65             TERM => 'TERM',
66             HUP => 'TERM',
67             },
68             );
69 110 50       323 if (defined $self->{spawn_interval}) {
70 110         272 $pm_args{trap_signals}{USR1} = [ 'TERM', $self->{spawn_interval} ];
71 110         140 $pm_args{spawn_interval} = $self->{spawn_interval};
72             }
73 110 50       397 if (defined $self->{err_respawn_interval}) {
74 0         0 $pm_args{err_respawn_interval} = $self->{err_respawn_interval};
75             }
76 110         785 my $pm = Parallel::Prefork->new(\%pm_args);
77 110         6746 while ($pm->signal_received !~ /^(TERM|USR1)$/) {
78 110 100       845 $pm->start and next;
79 97         13663824 srand((rand() * 2 ** 30) ^ $$ ^ time);
80 97         2165 $self->accept_loop($app, $self->_calc_reqs_per_child());
81 14         149 $pm->finish;
82             }
83 13         14386051 my $timeout = 1;
84 13 50       125 if ($self->{spawn_interval}) {
85             $timeout = $self->{spawn_interval} * $self->{max_workers}
86 0         0 }
87 13         154 while ($pm->wait_all_children($timeout)) {
88 0         0 $pm->signal_all_children('TERM');
89             }
90             } else {
91             # run directly, mainly for debugging
92 1     0   17 local $SIG{TERM} = sub { exit 0; };
  0         0  
93 1         2 while (1) {
94 1         2 $self->accept_loop($app, $self->_calc_reqs_per_child());
95             }
96             }
97             }
98              
99             sub _calc_reqs_per_child {
100 10098     10098   27842 my $self = shift;
101 10098         6909 my $max = $self->{max_reqs_per_child};
102 10098 100       9900 if (my $min = $self->{min_reqs_per_child}) {
103 10000         10949 return $max - int(($max - $min + 1) * rand);
104             } else {
105 98         6792 return $max;
106             }
107             }
108              
109             1;