@@ -1938,3 +1938,38 @@ def setUp(self):
1938
1938
'nova.compute.manager.ComputeManager.'
1939
1939
'_ensure_existing_node_identity' ,
1940
1940
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