# 서비스와 액션의 개념 및 차이점

#### 서비스의 개념

ROS2에서 서비스(Service)는 서버-클라이언트 통신 패턴을 따르는 구조로, \*\*요청(request)\*\*과 \*\*응답(response)\*\*의 흐름을 기반으로 동작한다. 서비스는 특정한 작업을 요청하는 클라이언트와, 그 요청을 처리하고 응답을 반환하는 서버로 이루어져 있다.

**서비스 흐름 다이어그램**

{% @mermaid/diagram content="sequenceDiagram
participant Client
participant Service\_Server
Client->>Service\_Server: Request
Service\_Server-->>Client: Response
" %}

**서비스의 특징**

* **단일 요청/응답 구조**: 서비스는 요청이 들어오면 서버가 요청을 처리하고 그에 대한 응답을 반환하는 방식으로 동작한다. 이때 클라이언트는 응답을 받을 때까지 대기할 수 있으며, 서버에서 응답을 줄 때까지 클라이언트는 다른 작업을 수행하지 못할 수 있다.
* **동기적 통신**: 서비스 호출은 일반적으로 동기적이며, 이는 클라이언트가 응답을 기다리면서 요청을 처리하는 동안 차단(blocking)될 수 있음을 의미한다.

서비스의 사용 예시:

```cpp
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"

void add(const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request,
         std::shared_ptr<example_interfaces::srv::AddTwoInts::Response> response)
{
  response->sum = request->a + request->b;
}

int main(int argc, char **argv)
{
  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("add_two_ints_server");
  auto service = node->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints", &add);
  rclcpp::spin(node);
  rclcpp::shutdown();
  return 0;
}
```

이 코드에서 서비스 서버는 두 정수를 더한 값을 클라이언트에게 반환하는 간단한 작업을 수행한다. 클라이언트는 해당 서비스에 요청을 보내고, 서버는 요청을 처리한 후 응답을 클라이언트에게 보내는 구조이다.

#### 액션의 개념

액션(Action)은 서비스와 유사하게 클라이언트-서버 통신을 기반으로 하지만, **비동기 작업**을 처리하는 데 더 적합하다. 액션은 긴 시간이 소요될 수 있는 작업을 처리하기 위해 설계되었으며, 중간에 피드백(feedback)을 제공할 수 있다. 또한, 작업이 진행 중인 상태에서 **취소**할 수 있는 기능을 제공한다.

**액션 흐름 다이어그램**

{% @mermaid/diagram content="sequenceDiagram
participant Client
participant Action\_Server
Client->>Action\_Server: Request
Action\_Server-->>Client: Feedback
Action\_Server-->>Client: Feedback
Action\_Server-->>Client: Result
" %}

**액션의 특징**

* **비동기적 통신**: 액션은 비동기적으로 동작하며, 클라이언트는 작업이 완료될 때까지 기다리지 않고 다른 작업을 계속 수행할 수 있다.
* **피드백 제공**: 액션은 작업이 진행 중인 동안 클라이언트에게 피드백을 제공할 수 있다. 이는 클라이언트가 현재 작업 상태를 실시간으로 확인할 수 있도록 해준다.
* **취소 가능성**: 클라이언트는 작업을 요청한 후 작업이 끝나기 전에 해당 작업을 취소할 수 있다. 이 기능은 작업이 오래 걸리거나 더 이상 필요하지 않을 때 유용하다.

액션의 사용 예시:

```cpp
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/action/fibonacci.hpp"
#include "rclcpp_action/rclcpp_action.hpp"

class FibonacciActionServer : public rclcpp::Node
{
public:
  using Fibonacci = example_interfaces::action::Fibonacci;
  using GoalHandleFibonacci = rclcpp_action::ServerGoalHandle<Fibonacci>;

  explicit FibonacciActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())
  : Node("fibonacci_action_server", options)
  {
    using namespace std::placeholders;
    this->action_server_ = rclcpp_action::create_server<Fibonacci>(
      this,
      "fibonacci",
      std::bind(&FibonacciActionServer::handle_goal, this, _1, _2),
      std::bind(&FibonacciActionServer::handle_cancel, this, _1),
      std::bind(&FibonacciActionServer::handle_accepted, this, _1));
  }

private:
  rclcpp_action::Server<Fibonacci>::SharedPtr action_server_;

  rclcpp_action::GoalResponse handle_goal(
    const rclcpp_action::GoalUUID & uuid,
    std::shared_ptr<const Fibonacci::Goal> goal)
  {
    RCLCPP_INFO(this->get_logger(), "Received goal request with order %d", goal->order);
    return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
  }

  rclcpp_action::CancelResponse handle_cancel(
    const std::shared_ptr<GoalHandleFibonacci> goal_handle)
  {
    RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
    return rclcpp_action::CancelResponse::ACCEPT;
  }

  void handle_accepted(const std::shared_ptr<GoalHandleFibonacci> goal_handle)
  {
    using namespace std::placeholders;
    std::thread{std::bind(&FibonacciActionServer::execute, this, _1), goal_handle}.detach();
  }

  void execute(const std::shared_ptr<GoalHandleFibonacci> goal_handle)
  {
    RCLCPP_INFO(this->get_logger(), "Executing goal");
    // 실제 Fibonacci 계산 수행
  }
};
```

이 코드는 피보나치 수열을 계산하는 액션 서버를 구현한 예시이다. 작업이 진행되는 동안 피드백을 제공하고, 클라이언트가 필요할 때 작업을 취소할 수 있다.

#### 서비스와 액션의 차이점

**1. 동기 vs 비동기**

서비스는 동기적인 통신 방식이다. 클라이언트는 서버에 요청을 보낸 후 응답을 받을 때까지 기다려야 한다. 이 방식은 짧은 시간에 완료되는 작업에 적합하지만, 긴 시간이 걸리는 작업에서는 효율적이지 않을 수 있다.\
반면 액션은 비동기적인 통신 방식을 지원한다. 클라이언트는 요청을 보낸 후 작업이 완료되기 전에도 다른 작업을 수행할 수 있으며, 작업이 진행 중인 동안 피드백을 받을 수 있다.

{% @mermaid/diagram content="graph TD
subgraph Service
A\[클라이언트] --> B\[요청]
B --> C\[서버]
C --> D\[응답]
D --> A
end

```
subgraph Action
    E[클라이언트] --> F[요청]
    F --> G[서버]
    G --> H[피드백]
    H --> E
    G --> I[응답]
    I --> E
end" %}
```

이를 수식으로 표현하면, 서비스의 경우 다음과 같이 클라이언트가 차단되는 동기적인 흐름이 발생한다.

$$
\text{Client\_Request} \xrightarrow{\text{동기}} \text{Server\_Response}
$$

반면에 액션의 경우 비동기적으로 피드백을 제공하며 작업을 완료하는 구조이다.

$$
\text{Client\_Request} \xrightarrow{\text{비동기}} \text{Server\_Feedback} \xrightarrow{\text{비동기}} \text{Server\_Completion}
$$

**2. 피드백 제공 여부**

서비스는 요청과 응답이 한 번에 이루어지기 때문에 중간에 피드백을 제공하지 않는다. 클라이언트는 요청을 보낸 후 완료된 응답을 받기 전까지 작업 진행 상태를 알 수 없다.\
반면, 액션은 작업이 완료되기 전에도 작업의 진행 상태를 클라이언트에게 피드백으로 제공할 수 있다. 이 기능은 긴 시간이 소요되는 작업에서 클라이언트가 현재 진행 상태를 확인할 수 있도록 돕는다.

**3. 작업의 취소**

서비스는 클라이언트가 요청을 보낸 후에는 취소할 수 없다. 서버는 클라이언트의 요청을 모두 처리한 후에 응답을 반환한다.\
반면에 액션은 작업이 진행되는 도중에 클라이언트가 작업을 취소할 수 있는 기능을 제공한다. 이 기능은 클라이언트가 작업을 더 이상 필요로 하지 않거나 다른 우선순위가 발생했을 때 유용하다.

**4. 사용 목적**

서비스는 상대적으로 빠르게 끝나는 작업에 적합하다. 예를 들어, 두 수의 덧셈과 같은 계산 작업은 서비스로 처리하기에 적합하다. 반면, 액션은 긴 시간이 걸리거나 중간 피드백이 필요한 작업에 적합하다. 예를 들어, 로봇이 목적지로 이동하는 동안 여러 경로를 탐색하고 현재 진행 상황을 계속해서 클라이언트에게 알리는 작업은 액션으로 처리하는 것이 더 적합하다.

**5. 상태 관리**

서비스는 요청과 응답만을 처리하며, 상태를 관리하지 않는다. 즉, 요청이 완료되면 상태가 유지되지 않는다.\
반면, 액션은 요청이 들어온 후 작업의 상태를 관리할 수 있다. 작업이 완료되기 전, 진행 중인 상태를 계속해서 업데이트할 수 있으며, 이 상태는 피드백을 통해 클라이언트에게 전달될 수 있다.

#### 서비스와 액션의 비교

| 항목        | 서비스                  | 액션                         |
| --------- | -------------------- | -------------------------- |
| **통신 방식** | 동기                   | 비동기                        |
| **작업 시간** | 짧은 시간의 작업에 적합        | 긴 시간의 작업에 적합               |
| **피드백**   | 없음                   | 작업의 중간 피드백 제공              |
| **취소 기능** | 없음                   | 작업 취소 가능                   |
| **사용 사례** | 즉각적인 센서 값 조회, 간단한 명령 | 로봇의 복잡한 동작, 시간이 많이 소요되는 작업 |

이와 같이, 서비스와 액션은 각기 다른 특성과 사용 시나리오를 가지고 있으며, 이를 적절히 활용함으로써 ROS2에서의 다양한 통신 요구를 만족시킬 수 있다.

#### 서비스와 액션의 선택 기준

서비스와 액션 중 어느 것을 사용할지 결정할 때는 작업의 성격과 요구 사항을 고려해야 한다. 만약 작업이 상대적으로 짧은 시간 내에 완료되고, 클라이언트가 응답을 받을 때까지 대기하는 방식이 적합하다면 서비스가 더 적절하다. 그러나 작업이 긴 시간이 걸리거나 중간에 상태를 확인할 필요가 있거나, 작업을 중도에 취소할 가능성이 있다면 액션이 더 적합할 것이다.

**사례 비교**

* **서비스 예시**: 로봇의 특정 센서 값을 요청하는 작업은 서비스로 처리하는 것이 적합하다. 요청에 대한 응답은 빠르게 완료되며, 중간에 피드백을 제공할 필요가 없다.
* **액션 예시**: 로봇의 경로 계획이나 이동 작업은 액션으로 처리하는 것이 적합하다. 이동 중에 현재 위치나 진행 상태를 피드백으로 제공할 수 있고, 중간에 경로를 변경하거나 취소할 수 있는 유연성이 필요하다.
