Merge lp:~cjwatson/rabbitfixture/fix-kill into lp:rabbitfixture

Proposed by Colin Watson
Status: Merged
Merged at revision: 52
Proposed branch: lp:~cjwatson/rabbitfixture/fix-kill
Merge into: lp:rabbitfixture
Diff against target: 103 lines (+35/-30)
1 file modified
rabbitfixture/server.py (+35/-30)
To merge this branch: bzr merge lp:~cjwatson/rabbitfixture/fix-kill
Reviewer Review Type Date Requested Status
Ioana Lasc (community) Approve
Review via email: mp+397242@code.launchpad.net

Commit message

Handle SIGCHLD in RabbitServerRunner.kill too.

To post a comment you must log in.
Revision history for this message
Ioana Lasc (ilasc) wrote :

looks good

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'rabbitfixture/server.py'
2--- rabbitfixture/server.py 2021-02-01 11:14:25 +0000
3+++ rabbitfixture/server.py 2021-02-01 11:49:40 +0000
4@@ -12,6 +12,7 @@
5 "RabbitServerResources",
6 ]
7
8+from contextlib import contextmanager
9 import errno
10 import logging
11 import os
12@@ -309,6 +310,34 @@
13 else:
14 raise Exception("RabbitMQ server is not running.")
15
16+ @contextmanager
17+ def _handle_sigchld(self):
18+ # The rabbitmq-server process we're trying to stop is our direct
19+ # child process, so we need to handle SIGCHLD in order for the
20+ # process to go away gracefully.
21+ def sigchld_handler(signum, frame):
22+ while True:
23+ try:
24+ pid, _ = os.waitpid(-1, os.WNOHANG)
25+ if not pid:
26+ break
27+ except OSError as e:
28+ if e.errno == errno.ECHILD:
29+ break
30+ raise
31+
32+ original_sigchld = signal.signal(signal.SIGCHLD, sigchld_handler)
33+ if original_sigchld is None:
34+ logging.warning(
35+ "Previous SIGCHLD handler was installed by non-Python code; "
36+ "will restore to default action instead.")
37+ original_sigchld = signal.SIG_DFL
38+
39+ try:
40+ yield
41+ finally:
42+ signal.signal(signal.SIGCHLD, original_sigchld)
43+
44 def kill(self):
45 """Kill the RabbitMQ server process.
46
47@@ -319,10 +348,11 @@
48 It is also useful to test your code against scenarios where the server
49 dies.
50 """
51- self._signal(signal.SIGKILL)
52- time.sleep(0.5)
53- if self.is_running():
54- raise Exception("RabbitMQ server just won't die.")
55+ with self._handle_sigchld():
56+ self._signal(signal.SIGKILL)
57+ time.sleep(0.5)
58+ if self.is_running():
59+ raise Exception("RabbitMQ server just won't die.")
60
61 def _spawn(self):
62 """Spawn the RabbitMQ server process."""
63@@ -387,29 +417,7 @@
64
65 def _stop(self):
66 """Stop the running server. Normally called by cleanups."""
67- def handle_sigchld(signum, frame):
68- while True:
69- try:
70- pid, _ = os.waitpid(-1, os.WNOHANG)
71- if not pid:
72- break
73- except OSError as e:
74- if e.errno == errno.ECHILD:
75- break
76- raise
77-
78- original_sigchld = None
79- try:
80- # The rabbitmq-server process we're trying to stop is our direct
81- # child process, so we need to handle SIGCHLD in order for the
82- # process to go away gracefully.
83- original_sigchld = signal.signal(signal.SIGCHLD, handle_sigchld)
84- if original_sigchld is None:
85- logging.warning(
86- "Previous SIGCHLD handler was installed by non-Python "
87- "code; will restore to default action instead.")
88- original_sigchld = signal.SIG_DFL
89-
90+ with self._handle_sigchld():
91 try:
92 self._request_stop()
93 # Wait for the node to go down...
94@@ -436,9 +444,6 @@
95 # Die!!!
96 if self.is_running():
97 self.kill()
98- finally:
99- if original_sigchld is not None:
100- signal.signal(signal.SIGCHLD, original_sigchld)
101
102 def _signal(self, code):
103 """Send a signal to the server process and all its children."""

Subscribers

People subscribed via source and target branches

to all changes: