|
1 | | -import os |
2 | | -import time |
3 | 1 | import errno |
| 2 | +import functools |
| 3 | +import os |
| 4 | +import signal |
4 | 5 | import shlex |
| 6 | +import time |
5 | 7 | import traceback |
6 | | -import signal |
7 | | -from functools import total_ordering |
8 | 8 |
|
9 | 9 | from supervisor.compat import maxint |
10 | 10 | from supervisor.compat import as_bytes |
|
30 | 30 |
|
31 | 31 | from supervisor.socket_manager import SocketManager |
32 | 32 |
|
33 | | -@total_ordering |
| 33 | +@functools.total_ordering |
34 | 34 | class Subprocess(object): |
35 | 35 |
|
36 | 36 | """A class to manage a subprocess.""" |
@@ -403,7 +403,8 @@ def give_up(self): |
403 | 403 | self.change_state(ProcessStates.FATAL) |
404 | 404 |
|
405 | 405 | def kill(self, sig): |
406 | | - """Send a signal to the subprocess. This may or may not kill it. |
| 406 | + """Send a signal to the subprocess with the intention to kill |
| 407 | + it (to make it exit). This may or may not actually kill it. |
407 | 408 |
|
408 | 409 | Return None if the signal was sent, or an error message string |
409 | 410 | if an error occurred or if the subprocess is not running. |
@@ -463,14 +464,23 @@ def kill(self, sig): |
463 | 464 | pid = -self.pid |
464 | 465 |
|
465 | 466 | try: |
466 | | - options.kill(pid, sig) |
| 467 | + try: |
| 468 | + options.kill(pid, sig) |
| 469 | + except OSError as exc: |
| 470 | + if exc.errno == errno.ESRCH: |
| 471 | + msg = ("unable to signal %s (pid %s), it probably just exited " |
| 472 | + "on its own: %s" % (processname, self.pid, str(exc))) |
| 473 | + options.logger.debug(msg) |
| 474 | + # we could change the state here but we intentionally do |
| 475 | + # not. we will do it during normal SIGCHLD processing. |
| 476 | + return None |
| 477 | + raise |
467 | 478 | except: |
468 | 479 | tb = traceback.format_exc() |
469 | 480 | msg = 'unknown problem killing %s (%s):%s' % (processname, |
470 | 481 | self.pid, tb) |
471 | 482 | options.logger.critical(msg) |
472 | 483 | self.change_state(ProcessStates.UNKNOWN) |
473 | | - self.pid = 0 |
474 | 484 | self.killing = False |
475 | 485 | self.delay = 0 |
476 | 486 | return msg |
@@ -502,14 +512,24 @@ def signal(self, sig): |
502 | 512 | ProcessStates.STOPPING) |
503 | 513 |
|
504 | 514 | try: |
505 | | - options.kill(self.pid, sig) |
| 515 | + try: |
| 516 | + options.kill(self.pid, sig) |
| 517 | + except OSError as exc: |
| 518 | + if exc.errno == errno.ESRCH: |
| 519 | + msg = ("unable to signal %s (pid %s), it probably just now exited " |
| 520 | + "on its own: %s" % (processname, self.pid, |
| 521 | + str(exc))) |
| 522 | + options.logger.debug(msg) |
| 523 | + # we could change the state here but we intentionally do |
| 524 | + # not. we will do it during normal SIGCHLD processing. |
| 525 | + return None |
| 526 | + raise |
506 | 527 | except: |
507 | 528 | tb = traceback.format_exc() |
508 | 529 | msg = 'unknown problem sending sig %s (%s):%s' % ( |
509 | 530 | processname, self.pid, tb) |
510 | 531 | options.logger.critical(msg) |
511 | 532 | self.change_state(ProcessStates.UNKNOWN) |
512 | | - self.pid = 0 |
513 | 533 | return msg |
514 | 534 |
|
515 | 535 | return None |
@@ -753,7 +773,7 @@ def _prepare_child_fds(self): |
753 | 773 | for i in range(3, options.minfds): |
754 | 774 | options.close_fd(i) |
755 | 775 |
|
756 | | -@total_ordering |
| 776 | +@functools.total_ordering |
757 | 777 | class ProcessGroupBase(object): |
758 | 778 | def __init__(self, config): |
759 | 779 | self.config = config |
|
0 commit comments