\ Stop workers :attr graceful: boolean, If True (the default) workers will be killed gracefully (ie. trying to wait for the current connection)
(self, graceful=True)
| 413 | return signals |
| 414 | |
| 415 | def stop(self, graceful=True): |
| 416 | """\ |
| 417 | Stop workers |
| 418 | |
| 419 | :attr graceful: boolean, If True (the default) workers will be |
| 420 | killed gracefully (ie. trying to wait for the current connection) |
| 421 | """ |
| 422 | unlink = ( |
| 423 | self.reexec_pid == self.master_pid == 0 |
| 424 | and not self.systemd |
| 425 | and not self.cfg.reuse_port |
| 426 | ) |
| 427 | sock.close_sockets(self.LISTENERS, unlink) |
| 428 | |
| 429 | self.LISTENERS = [] |
| 430 | sig = signal.SIGTERM |
| 431 | if not graceful: |
| 432 | sig = signal.SIGQUIT |
| 433 | limit = time.time() + self.cfg.graceful_timeout |
| 434 | |
| 435 | # Stop dirty arbiter |
| 436 | if self.dirty_arbiter_pid: |
| 437 | self.kill_dirty_arbiter(sig) |
| 438 | |
| 439 | # instruct the workers to exit |
| 440 | self.kill_workers(sig) |
| 441 | # wait until the graceful timeout |
| 442 | quick_shutdown = not graceful |
| 443 | while (self.WORKERS or self.dirty_arbiter_pid) and time.time() < limit: |
| 444 | # Check for SIGINT/SIGQUIT to trigger quick shutdown |
| 445 | if not quick_shutdown: |
| 446 | try: |
| 447 | pending_sig = self.SIG_QUEUE.get_nowait() |
| 448 | if pending_sig in (signal.SIGINT, signal.SIGQUIT): |
| 449 | self.log.info("Quick shutdown requested") |
| 450 | quick_shutdown = True |
| 451 | self.kill_workers(signal.SIGQUIT) |
| 452 | if self.dirty_arbiter_pid: |
| 453 | self.kill_dirty_arbiter(signal.SIGQUIT) |
| 454 | # Give workers a short time to exit cleanly |
| 455 | limit = time.time() + 2.0 |
| 456 | except Exception: |
| 457 | pass |
| 458 | self.reap_workers() |
| 459 | self.reap_dirty_arbiter() |
| 460 | time.sleep(0.1) |
| 461 | |
| 462 | self.kill_workers(signal.SIGKILL) |
| 463 | if self.dirty_arbiter_pid: |
| 464 | self.kill_dirty_arbiter(signal.SIGKILL) |
| 465 | # Final reap to clean up any remaining zombies |
| 466 | self.reap_workers() |
| 467 | self.reap_dirty_arbiter() |
| 468 | |
| 469 | def reexec(self): |
| 470 | """\ |