Server.pm 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package TPSGI::Server;
  2. use strict;
  3. use warnings;
  4. use parent qw{Starman::Server};
  5. =head1 TPSGI::Server
  6. Starman::Server, with workers that answer every connection they accept before
  7. a HUP retires them.
  8. =head2 Why
  9. A HUP to Starman's parent sends HUP to every worker. Net::Server::PreFork's
  10. handler for it exits on the spot unless the worker is C<connected>, and
  11. run_child() only sets that flag in the statement after accept() returns. Perl
  12. runs the handler between those two, so a worker which had just accepted a
  13. connection exited holding it: the kernel reset the connection, and nginx
  14. answered the client with a 502. tPSGI HUPs its parent after every save, and
  15. the browser's next request lands exactly then.
  16. Here the handler only marks the worker HUPed and done, and accept() returns 1
  17. whenever it is holding a connection. A worker blocked in accept() still
  18. retires at once, since the HUP interrupts the accept and nothing was taken. One
  19. which took a connection answers it, and done() retires it afterwards, as it
  20. does a worker that was busy when the HUP came.
  21. This depends on how Net::Server's accept() and run_child() use C<_HUP>,
  22. C<SigHUPed> and C<client>. t/TPSGI-Server.t pins that.
  23. =head2 child_init_hook
  24. Starman's, then the HUP handler described above. It replaces the one
  25. Net::Server::PreFork installs in run_child(), which runs before this hook.
  26. =cut
  27. sub child_init_hook {
  28. my $self = shift;
  29. $self->SUPER::child_init_hook(@_);
  30. my $prop = $self->{server};
  31. $SIG{HUP} = sub {
  32. $prop->{SigHUPed} = 1;
  33. # Makes Net::Server's accept() return rather than retry, so a worker
  34. # waiting in it retires now instead of after its next request.
  35. $prop->{_HUP} = 1;
  36. };
  37. return;
  38. }
  39. =head2 accept() = BOOL
  40. True when there is a connection to answer, even when a HUP made
  41. Net::Server::accept() say otherwise.
  42. =cut
  43. sub accept { ## no critic (ProhibitBuiltinHomonyms) -- Net::Server's method, overridden
  44. my $self = shift;
  45. my $prop = $self->{server};
  46. # So a connection from the last request cannot pass for a new one.
  47. delete $prop->{client};
  48. return 1 if $self->SUPER::accept(@_);
  49. return $prop->{client} ? 1 : 0;
  50. }
  51. 1;