ros2 / ros2/rclcpp

ROS 2 services are not 1 to 1 communication: responses are copied and sent to all clients

Open
#2,397 1 comment 1 reaction 1 assignee View on GitHub

@fujitatomoya is already working on this.

Since Jan 4, 2024.

backlog
Dominant language
C++
Stars
805
Forks
564
Avg merge
1d 17h
Merged PRs (30d)
27

Description

Issue report

Currently if there are 2 (or more) clients with the same /service_name, both will get the server response (one will silently discard it after noticing it wasn't for him).

This has CPU & memory performances implications - in many cases server responses can be quite big - thus unnecessary copies and de-serialization of responses happen, while there could be multiple clients with same name (not uncommon situation).

I verified this problem with rmw_cyclonedds & rmw_fastrtps , on current rolling, humble & galactic.

  // Example
  auto service = node1->create_service<SetBool>("srv_name");
  auto client_1 = node2->create_client<SetBool>("srv_name");
  auto client_2 = node3->create_client<SetBool>("srv_name");

  client_1->async_send_request(...);
  
  // Spin service, so it will get the request and produce a response.
  // The response is received in both clients - one will silently discard it

A full example can be found here, where I'm also using a service message with an 8MB request / 8MB response to better appreciate the performance consequences.

With the mentioned example using the mentioned service, I can compute a CPU FlameGraph showing the difference between having a single client vs having 2 clients with same /service_name, where we can see the extra CPU time overhead:

CPU_FlameGraph_srv_cli_double_delivery

In a one-to-one client-server communication model, a client sends a request to the server, and the server should respond to that specific client.

It'd be nice to find a way to comply with this model. Maybe the Service can store the Client's endpoint, and repond only to it.

Note that this issue doesn't happen if we use intra-process communication between clients & services, where the service only responds to the client who made the request.

The issue was noticed thanks to a log I added in the past, which would be nice to include in rolling:

[ERROR] [1699640383.717414288] [rclcpp]: Error in take_type_erased_response: RCL_RET_CLIENT_TAKE_FAILED. Service name: /persistent_params/list_parameters

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.