Server.pm 2.4 KB

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