Skip to content

Commit 646fc51

Browse files
fwieselratailor
authored andcommitted
Transport context to all threads
The nova.utils.spawn and spawn_n methods transport the context (and profiling information) to the newly created threads. But the same isn't done when submitting work to thread-pools in the ComputeManager. The code doing that for spawn and spawn_n is extracted to a new function and called to submit the work to the thread-pools. Closes-Bug: #1962574 Change-Id: I9085deaa8cf0b167d87db68e4afc4a463c00569c
1 parent 3b4378c commit 646fc51

File tree

4 files changed

+37
-29
lines changed

4 files changed

+37
-29
lines changed

nova/compute/manager.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8621,7 +8621,8 @@ def live_migration(self, context, dest, instance, block_migration,
86218621
# in order to be able to track and abort it in the future.
86228622
self._waiting_live_migrations[instance.uuid] = (None, None)
86238623
try:
8624-
future = self._live_migration_executor.submit(
8624+
future = nova.utils.pass_context(
8625+
self._live_migration_executor.submit,
86258626
self._do_live_migration, context, dest, instance,
86268627
block_migration, migration, migrate_data)
86278628
self._waiting_live_migrations[instance.uuid] = (migration, future)
@@ -9866,7 +9867,9 @@ def query_driver_power_state_and_sync():
98669867
else:
98679868
LOG.debug('Triggering sync for uuid %s', uuid)
98689869
self._syncs_in_progress[uuid] = True
9869-
self._sync_power_pool.spawn_n(_sync, db_instance)
9870+
nova.utils.pass_context(self._sync_power_pool.spawn_n,
9871+
_sync,
9872+
db_instance)
98709873

98719874
def _query_driver_power_state_and_sync(self, context, db_instance):
98729875
if db_instance.task_state is not None:

nova/conductor/manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,8 +2049,8 @@ def skipped_host(context, host, image_ids):
20492049
skipped_host(target_ctxt, host, image_ids)
20502050
continue
20512051

2052-
fetch_pool.spawn_n(wrap_cache_images, target_ctxt, host,
2053-
image_ids)
2052+
utils.pass_context(fetch_pool.spawn_n, wrap_cache_images,
2053+
target_ctxt, host, image_ids)
20542054

20552055
# Wait until all those things finish
20562056
fetch_pool.waitall()

nova/tests/unit/compute/test_compute_mgr.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9154,9 +9154,15 @@ def test_get_serial_console(self, mock_console_obj, mock_elevated):
91549154
self.assertEqual(driver_console.get_connection_info.return_value,
91559155
console)
91569156

9157+
@mock.patch('nova.utils.pass_context')
91579158
@mock.patch('nova.compute.manager.ComputeManager.'
91589159
'_do_live_migration')
9159-
def _test_max_concurrent_live(self, mock_lm):
9160+
def _test_max_concurrent_live(self, mock_lm, mock_pass_context):
9161+
# pass_context wraps the function, which doesn't work with a mock
9162+
# So we simply mock it too
9163+
def _mock_pass_context(runner, func, *args, **kwargs):
9164+
return runner(func, *args, **kwargs)
9165+
mock_pass_context.side_effect = _mock_pass_context
91609166

91619167
@mock.patch('nova.objects.Migration.save')
91629168
def _do_it(mock_mig_save):

nova/utils.py

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -632,15 +632,13 @@ def _serialize_profile_info():
632632
return trace_info
633633

634634

635-
def spawn(func, *args, **kwargs):
636-
"""Passthrough method for eventlet.spawn.
637-
638-
This utility exists so that it can be stubbed for testing without
639-
interfering with the service spawns.
635+
def pass_context(runner, func, *args, **kwargs):
636+
"""Generalised passthrough method
640637
641-
It will also grab the context from the threadlocal store and add it to
642-
the store on the new thread. This allows for continuity in logging the
643-
context when using this method to spawn a new thread.
638+
It will grab the context from the threadlocal store and add it to
639+
the store on the runner. This allows for continuity in logging the
640+
context when using this method to spawn a new thread through the
641+
runner function
644642
"""
645643
_context = common_context.get_current()
646644
profiler_info = _serialize_profile_info()
@@ -655,11 +653,11 @@ def context_wrapper(*args, **kwargs):
655653
profiler.init(**profiler_info)
656654
return func(*args, **kwargs)
657655

658-
return eventlet.spawn(context_wrapper, *args, **kwargs)
656+
return runner(context_wrapper, *args, **kwargs)
659657

660658

661-
def spawn_n(func, *args, **kwargs):
662-
"""Passthrough method for eventlet.spawn_n.
659+
def spawn(func, *args, **kwargs):
660+
"""Passthrough method for eventlet.spawn.
663661
664662
This utility exists so that it can be stubbed for testing without
665663
interfering with the service spawns.
@@ -668,25 +666,26 @@ def spawn_n(func, *args, **kwargs):
668666
the store on the new thread. This allows for continuity in logging the
669667
context when using this method to spawn a new thread.
670668
"""
671-
_context = common_context.get_current()
672-
profiler_info = _serialize_profile_info()
673669

674-
@functools.wraps(func)
675-
def context_wrapper(*args, **kwargs):
676-
# NOTE: If update_store is not called after spawn_n it won't be
677-
# available for the logger to pull from threadlocal storage.
678-
if _context is not None:
679-
_context.update_store()
680-
if profiler_info and profiler:
681-
profiler.init(**profiler_info)
682-
func(*args, **kwargs)
670+
return pass_context(eventlet.spawn, func, *args, **kwargs)
671+
672+
673+
def spawn_n(func, *args, **kwargs):
674+
"""Passthrough method for eventlet.spawn_n.
675+
676+
This utility exists so that it can be stubbed for testing without
677+
interfering with the service spawns.
683678
684-
eventlet.spawn_n(context_wrapper, *args, **kwargs)
679+
It will also grab the context from the threadlocal store and add it to
680+
the store on the new thread. This allows for continuity in logging the
681+
context when using this method to spawn a new thread.
682+
"""
683+
pass_context(eventlet.spawn_n, func, *args, **kwargs)
685684

686685

687686
def tpool_execute(func, *args, **kwargs):
688687
"""Run func in a native thread"""
689-
tpool.execute(func, *args, **kwargs)
688+
return pass_context(tpool.execute, func, *args, **kwargs)
690689

691690

692691
def is_none_string(val):

0 commit comments

Comments
 (0)