Skip to content

Commit 8d82979

Browse files
committed
Fix race with launch context changes when loading composable nodes
This bug was discovered when trying load composable nodes from a GroupAction. The ROS namespace (and presumably other remaps) pushed onto the context stack was popped after the LoadComposableNodes execute() function finished. But because the loading happens asynchronously, we need to make sure we get the necessary information from the context before execute() finishes. Signed-off-by: Jacob Perron <[email protected]>
1 parent 1f0ea9f commit 8d82979

File tree

1 file changed

+16
-10
lines changed

1 file changed

+16
-10
lines changed

launch_ros/launch_ros/actions/load_composable_nodes.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,13 @@ def __init__(
8282

8383
def _load_node(
8484
self,
85-
composable_node_description: ComposableNode,
85+
request: composition_interfaces.srv.LoadNode.Request,
8686
context: LaunchContext
8787
) -> None:
8888
"""
8989
Load node synchronously.
9090
91-
:param composable_node_description: description of composable node to be loaded
91+
:param request: service request to load a node
9292
:param context: current launch context
9393
"""
9494
while not self.__rclpy_load_node_client.wait_for_service(timeout_sec=1.0):
@@ -99,7 +99,6 @@ def _load_node(
9999
)
100100
)
101101
return
102-
request = get_composable_node_load_request(composable_node_description, context)
103102
response = self.__rclpy_load_node_client.call(request)
104103
node_name = response.full_node_name if response.full_node_name else request.node_name
105104
if response.success:
@@ -125,7 +124,7 @@ def _load_node(
125124

126125
def _load_in_sequence(
127126
self,
128-
composable_node_descriptions: List[ComposableNode],
127+
load_node_requests: List[composition_interfaces.srv.LoadNode.Request],
129128
context: LaunchContext
130129
) -> None:
131130
"""
@@ -134,13 +133,13 @@ def _load_in_sequence(
134133
:param composable_node_descriptions: descriptions of composable nodes to be loaded
135134
:param context: current launch context
136135
"""
137-
next_composable_node_description = composable_node_descriptions[0]
138-
composable_node_descriptions = composable_node_descriptions[1:]
139-
self._load_node(next_composable_node_description, context)
140-
if len(composable_node_descriptions) > 0:
136+
next_load_node_request = load_node_requests[0]
137+
load_node_requests = load_node_requests[1:]
138+
self._load_node(next_load_node_request, context)
139+
if len(load_node_requests) > 0:
141140
context.add_completion_future(
142141
context.asyncio_loop.run_in_executor(
143-
None, self._load_in_sequence, composable_node_descriptions, context
142+
None, self._load_in_sequence, load_node_requests, context
144143
)
145144
)
146145

@@ -169,9 +168,16 @@ def execute(
169168
)
170169
)
171170

171+
# Generate load requests before execute() exits to avoid race with context changing
172+
# due to scope change (e.g. if loading nodes from within a GroupAction).
173+
load_node_requests = [
174+
get_composable_node_load_request(node_description, context)
175+
for node_description in self.__composable_node_descriptions
176+
]
177+
172178
context.add_completion_future(
173179
context.asyncio_loop.run_in_executor(
174-
None, self._load_in_sequence, self.__composable_node_descriptions, context
180+
None, self._load_in_sequence, load_node_requests, context
175181
)
176182
)
177183

0 commit comments

Comments
 (0)