27.6.1 콜백 내부 치명적 예외 발생 시 전역 이그제큐터 패닉 격리 블록 체계
ROS2 런타임 환경에서 콜백 함수는 이그제큐터(Executor)의 이벤트 루프에 의해 스레드 컨텍스트 내에서 비동기적으로 호출된다. 단일 노드 또는 다중 노드 시스템에서 특정 노드의 콜백 내부에서 처리되지 않은 예외(Unhandled Exception)가 발생할 경우, 해당 예외는 이그제큐터 스레드로 전파되어 전체 프로세스의 패닉(Panic) 및 강제 종료를 유발할 수 있다. 이는 고신뢰성이 요구되는 자율 에이전트 드론 시스템에서 전체 제어 루프의 치명적인 장애를 의미하므로, 콜백 내부의 예외가 이그제큐터 층위로 전파되지 않도록 하는 격리 블록 체계의 구축이 필수적이다.
1. 이그제큐터 패닉 구조와 콜백 예외 전파
rclcpp 및 rclpy API 기반의 노드 환경에서, 콜백 인터페이스는 기본적으로 std::function 또는 이에 준하는 호출 가능(Callable) 객체 형태로 이그제큐터의 작업 큐(Work Queue)에 등록된다. 이그제큐터는 큐에서 콜백을 가져와 실행하며, 이 과정에서 예외가 발생하고 내부적으로 포착(catch)되지 않으면, C++ 런타임은 std::terminate()를 호출하게 된다.
std::terminate() 함수의 호출은 스택 풀기(Stack Unwinding)를 완전하게 보장하지 않은 채 프로세스를 즉각 중단시키는 요인이 되며, 메모리 자원 반환 누락은 물론 하드웨어 통신 채널에 불완전한 장치 상태를 남기는 결과를 초래한다. 따라서 ROS2 아키텍처에서의 안정적인 코드 베이스는 이그제큐터가 예외를 인지하기 이전에, 콜백 계층의 경계면에서 모든 예외를 차단하는 엄격한 격리 블록(Isolation Block) 설계를 요구한다.
2. RCLCPP 프레임워크에서의 예외 격리 체계 설계
C++ 환경의 rclcpp 프레임워크를 사용할 때, 프로세스 패닉을 방지하는 가장 일차적인 격리 수단은 콜백의 전역을 감싸는 로컬 예외 처리(Try-Catch) 블록이다. 이 때 표준 예외 클래스인 std::exception 파생 타입들뿐만 아니라, 시스템 콜 수준에서 발생하는 비표준 치명적 에러까지 모두 포착해야 이그제큐터의 생존성을 온전히 보장할 수 있다.
격리 체계는 콜백 함수 호출의 진입점과 반환점 사이의 모든 비즈니스 로직을 감싸는 보호 영역을 정의하여 구현한다.
void SystemMonitorNode::hardware_state_callback(const std_msgs::msg::String::SharedPtr msg)
{
try {
// 비즈니스 로직 및 상태 업데이트 영역 블록
process_hardware_data(msg);
} catch (const rclcpp::exceptions::RCLError & e) {
// ROS2 런타임 내부의 통신 계층 에러 처리
RCLCPP_ERROR(this->get_logger(), "RCL 미들웨어 계층 예외 발생: %s", e.what());
} catch (const std::exception & e) {
// C++ 표준 예외 및 사용자 정의 비즈니스 로직 예외 처리
RCLCPP_ERROR(this->get_logger(), "표준 런타임 예외 발생: %s", e.what());
} catch (...) {
// C++ 타입 시스템 외부의 비표준 예외 포착 체계
RCLCPP_FATAL(this->get_logger(), "치명적 언타입 예외 발생. 이그제큐터 전파 차단 완료.");
}
}
위와 같은 구조적 격리 블록은 처리 로직에서 파생되는 모든 이상 동작을 해당 콜백의 스코프(Scope) 내부로 한정 짓는다. 이를 통해 콜백을 실행하던 스레드가 붕괴 없이 안전하게 반환되어 이그제큐터 풀(Executor Pool)로 환원되도록 유도하며, 단일 콜백의 처리 실패가 다른 노드의 이벤트 처리로 파급되는 종속적 오류를 차단한다.
3. 다중 스레드 이그제큐터 시스템의 병렬성 제약 방어
다중 스레드 이그제큐터(Multi-threaded Executor)를 활용하는 병렬 처리 아키텍처에서는, 특정 콜백에서의 예외 격리 실패가 단순히 개별 스레드 하나의 소멸에 그치지 않고 공유된 스레드 풀 전체의 오염과 제어 흐름의 교착 상태(Deadlock)를 유발할 위험이 있다. 예를 들어, 예외 발생으로 인해 뮤텍스(Mutex)의 잠금이 해제되지 않은 상태로 스레드가 강제 소멸하면, 이후 동일 자원에 접근하려는 다른 콜백 스레드들까지 무한 대기 상태에 직면하게 된다.
따라서 멀티 스레딩 기반의 이그제큐터를 운영할 때는 Try-Catch 기반의 제어 흐름 격리뿐만 아니라, 자원 획득 시 RAII(Resource Acquisition Is Initialization) 패턴이나 락 가드(Lock Guard)와 같은 블록 범위 기반의 자원 관리 객체가 예외 발생 시 스택 풀림과 동시에 해제되도록 설계해야 한다. 생명주기와 자원을 동기화하는 기법이 통합되어야만, 예외 상황 속에서도 전역 자원 상태의 무결성을 유지할 수 있다.
4. 진단 신호 발신 및 결함 내성 파이프라인 연계
콜백 내부에서 예외를 강제 포착하여 이그제큐터의 프로세스 패닉을 억제하는 조치만으로는 결함 내성(Fault Tolerance)의 완벽한 달성을 논하기 어렵다. 예외 격리는 런타임 붕괴를 지연시켰을 뿐, 해당 콜백에 요구되던 원래의 사이버 물리 시스템 제어 데이터 갱신은 누락되었기 때문이다.
이러한 한계를 극복하기 위해서는 격리 블록 내부에서 예외를 포착한 직후 단순한 콘솔 출력에 머무르지 않고, 시스템 전반의 상태 모니터링 노드 지표로 진단(Diagnostic) 신호를 발신해야 한다. 매니지드 라이프사이클 노드(Managed Lifecycle Node)를 운용 중이라면, 내부적으로 트리거 이벤트를 발생시켜 노드의 상태 맵을 ’Unconfigured’나 ‘Error’ 상태로 명시적으로 전이시키는 후속 파이프라인 처리가 수반되어야 한다. 이는 예외 격리 블록이 시스템의 로버스트 제어 아키텍처 관점에서 자율적 에러 복원 및 페일 세이프(Fail-safe) 체계로 연결되는 출발점으로서 작용하게 한다.