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

Proposed by Colin Watson
Status: Merged
Merged at revision: 50
Proposed branch: lp:~cjwatson/rabbitfixture/fix-stop
Merge into: lp:rabbitfixture
Diff against target: 107 lines (+53/-22)
2 files modified
NEWS.rst (+3/-0)
rabbitfixture/server.py (+50/-22)
To merge this branch: bzr merge lp:~cjwatson/rabbitfixture/fix-stop
Reviewer Review Type Date Requested Status
Tom Wardill (community) Approve
Review via email: mp+397232@code.launchpad.net

Commit message

Handle SIGCHLD while stopping the RabbitServerRunner fixture.

Description of the change

The rabbitmq-server process we're trying to stop is our direct child process.

To post a comment you must log in.
Revision history for this message
Tom Wardill (twom) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS.rst'
2--- NEWS.rst 2021-02-01 10:26:51 +0000
3+++ NEWS.rst 2021-02-01 10:41:20 +0000
4@@ -6,6 +6,9 @@
5 =====
6
7 - Add tox testing support and drop buildout.
8+- Handle ``SIGCHLD`` while stopping the ``RabbitServerRunner`` fixture,
9+ since the ``rabbitmq-server`` process we're trying to stop is our direct
10+ child process.
11
12 0.4.2 (2019-08-23)
13 ==================
14
15=== modified file 'rabbitfixture/server.py'
16--- rabbitfixture/server.py 2019-08-21 13:55:49 +0000
17+++ rabbitfixture/server.py 2021-02-01 10:41:20 +0000
18@@ -12,6 +12,8 @@
19 "RabbitServerResources",
20 ]
21
22+import errno
23+import logging
24 import os
25 import re
26 import signal
27@@ -384,32 +386,58 @@
28
29 def _stop(self):
30 """Stop the running server. Normally called by cleanups."""
31+ def handle_sigchld(signum, frame):
32+ while True:
33+ try:
34+ pid, _ = os.waitpid(-1, os.WNOHANG)
35+ if not pid:
36+ break
37+ except OSError as e:
38+ if e.errno == errno.ECHILD:
39+ break
40+ raise
41+
42+ original_sigchld = None
43 try:
44- self._request_stop()
45- # Wait for the node to go down...
46- timeout = time.time() + self.environment.ctltimeout
47+ # The rabbitmq-server process we're trying to stop is our direct
48+ # child process, so we need to handle SIGCHLD in order for the
49+ # process to go away gracefully.
50+ original_sigchld = signal.signal(signal.SIGCHLD, handle_sigchld)
51+ if original_sigchld is None:
52+ logging.warning(
53+ "Previous SIGCHLD handler was installed by non-Python "
54+ "code; will restore to default action instead.")
55+ original_sigchld = signal.SIG_DFL
56+
57+ try:
58+ self._request_stop()
59+ # Wait for the node to go down...
60+ timeout = time.time() + self.environment.ctltimeout
61+ while time.time() < timeout:
62+ if not self.environment.is_node_running():
63+ break
64+ time.sleep(0.3)
65+ else:
66+ raise Exception(
67+ "Timeout waiting for RabbitMQ node to go down.")
68+ except subprocess.TimeoutExpired:
69+ # Go straight to killing the process directly.
70+ timeout = time.time()
71+
72+ # Wait for the process to end...
73+ timeout = max(timeout, time.time() + self.environment.ctltimeout)
74 while time.time() < timeout:
75- if not self.environment.is_node_running():
76+ if not self.is_running():
77 break
78- time.sleep(0.3)
79+ self._signal(signal.SIGTERM)
80+ time.sleep(0.1)
81 else:
82- raise Exception(
83- "Timeout waiting for RabbitMQ node to go down.")
84- except subprocess.TimeoutExpired:
85- # Go straight to killing the process directly.
86- timeout = time.time()
87-
88- # Wait for the process to end...
89- timeout = max(timeout, time.time() + self.environment.ctltimeout)
90- while time.time() < timeout:
91- if not self.is_running():
92- break
93- self._signal(signal.SIGTERM)
94- time.sleep(0.1)
95- else:
96- # Die!!!
97- if self.is_running():
98- self.kill()
99+ # Die!!!
100+ if self.is_running():
101+ self.kill()
102+ finally:
103+ if original_sigchld is not None:
104+ signal.signal(signal.SIGCHLD, original_sigchld)
105
106 def _signal(self, code):
107 """Send a signal to the server process and all its children."""

Subscribers

People subscribed via source and target branches

to all changes: