Skip to content

Commit 22cccb9

Browse files
melwittgibizer
authored andcommitted
tests: Use GreenThreadPoolExecutor.shutdown(wait=True)
We are still having some issues in the gate where greenlets from previous tests continue to run while the next test starts, causing false negative failures in unit or functional test jobs. This adds a new fixture that will ensure GreenThreadPoolExecutor.shutdown() is called with wait=True, to wait for greenlets in the pool to finish running before moving on. In local testing, doing this does not appear to adversely affect test run times, which was my primary concern. As a baseline, I ran a subset of functional tests in a loop until failure without the patch and after 11 hours, I got a failure reproducing the bug. With the patch, running the same subset of functional tests in a loop has been running for 24 hours and has not failed yet. Based on this, I think it may be worth trying this out to see if it will help stability of our unit and functional test jobs. And if it ends up impacting test run times or causes other issues, we can revert it. Partial-Bug: #1946339 Change-Id: Ia916310522b007061660172fa4d63d0fde9a55ac (cherry picked from commit c095cfe)
1 parent d045b69 commit 22cccb9

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

nova/test.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,13 @@ def setUp(self):
317317
# all other tests.
318318
scheduler_utils.reset_globals()
319319

320+
# Wait for bare greenlets spawn_n()'ed from a GreenThreadPoolExecutor
321+
# to finish before moving on from the test. When greenlets from a
322+
# previous test remain running, they may attempt to access structures
323+
# (like the database) that have already been torn down and can cause
324+
# the currently running test to fail.
325+
self.useFixture(nova_fixtures.GreenThreadPoolShutdownWait())
326+
320327
def _setup_cells(self):
321328
"""Setup a normal cellsv2 environment.
322329

nova/tests/fixtures/nova.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1938,3 +1938,38 @@ def setUp(self):
19381938
'nova.compute.manager.ComputeManager.'
19391939
'_ensure_existing_node_identity',
19401940
mock.DEFAULT))
1941+
1942+
1943+
class GreenThreadPoolShutdownWait(fixtures.Fixture):
1944+
"""Always wait for greenlets in greenpool to finish.
1945+
1946+
We use the futurist.GreenThreadPoolExecutor, for example, in compute
1947+
manager to run live migration jobs. It runs those jobs in bare greenlets
1948+
created by eventlet.spawn_n(). Bare greenlets cannot be killed the same
1949+
way as GreenThreads created by eventlet.spawn().
1950+
1951+
Because they cannot be killed, in the test environment we must either let
1952+
them run to completion or move on while they are still running (which can
1953+
cause test failures as the leaked greenlets attempt to access structures
1954+
that have already been torn down).
1955+
1956+
When a compute service is stopped by Service.stop(), the compute manager's
1957+
cleanup_host() method is called and while cleaning up, the compute manager
1958+
calls the GreenThreadPoolExecutor.shutdown() method with wait=False. This
1959+
means that a test running GreenThreadPoolExecutor jobs will not wait for
1960+
the bare greenlets to finish running -- it will instead move on immediately
1961+
while greenlets are still running.
1962+
1963+
This fixture will ensure GreenThreadPoolExecutor.shutdown() is always
1964+
called with wait=True in an effort to reduce the number of leaked bare
1965+
greenlets.
1966+
1967+
See https://bugs.launchpad.net/nova/+bug/1946339 for details.
1968+
"""
1969+
1970+
def setUp(self):
1971+
super().setUp()
1972+
real_shutdown = futurist.GreenThreadPoolExecutor.shutdown
1973+
self.useFixture(fixtures.MockPatch(
1974+
'futurist.GreenThreadPoolExecutor.shutdown',
1975+
lambda self, wait: real_shutdown(self, wait=True)))

0 commit comments

Comments
 (0)