1. iFlow에서 에러를 무시하면 생기는 일
SAP BTP Integration Suite(Cloud Integration capability)에서 Integration Flow(iFlow)를 운영하다 보면, 수신 시스템의 일시적 다운, 네트워크 타임아웃, 잘못된 페이로드 같은 장애는 반드시 발생합니다. 문제는 에러 처리 전략이 없는 iFlow에서는 실패한 메시지가 그대로 유실된다는 점입니다. 예를 들어 온라인 주문 시스템에서 S/4HANA로 판매오더를 전송하는 iFlow가 새벽에 30건 실패했다면, 모니터링 화면에는 "Failed"만 남고 원본 페이로드는 사라집니다. 재전송하려면 송신 시스템에 다시 요청해야 하는데, 송신 측이 fire-and-forget 방식이라면 복구 자체가 불가능합니다.
이 글에서는 이런 메시지 유실을 막는 대표적인 통합 패턴인 Dead Letter Channel을 SAP Integration Suite에서 3단계로 구현하는 방법을 다룹니다. 읽고 나면 다음을 직접 구성할 수 있습니다.
- Exception Subprocess로 에러를 가로채 원본 페이로드 보존하기
- JMS 큐 기반 Dead Letter Queue 구성하기
- 재시도 횟수 제한이 있는 Retry 메커니즘 만들기
대상 독자는 iFlow를 만들어 배포해 본 경험이 있는 중급 개발자입니다. Content Modifier, Router 등 기본 플로우 스텝과 Groovy 스크립트 기초를 알고 있다면 충분합니다.
2. Dead Letter Channel 패턴이란
Dead Letter Channel은 Enterprise Integration Patterns(EIP)에 정의된 패턴으로, 정상 경로로 전달할 수 없는 메시지를 별도의 보관 채널로 옮겨 유실을 방지하는 방식입니다. 우체국의 "배달 불능 우편물 보관소"에 비유할 수 있습니다. 주소가 잘못된 편지를 그냥 버리지 않고 별도 보관소에 모아 두었다가, 주소를 확인해 재배달하거나 반송하는 것과 같은 원리입니다.
메시지 흐름을 도식화하면 다음과 같습니다.
송신 시스템 → [입구 iFlow] → JMS 큐(inbound)
│
[처리 iFlow] ──성공──→ 수신 시스템
│
실패 (n회 재시도 초과)
↓
JMS 큐(dead letter) → 알림 + 수동/자동 재처리
핵심은 세 가지입니다. 첫째, 처리와 수신을 비동기로 분리(decoupling)해 수신 시스템 장애가 송신 측에 전파되지 않게 합니다. 둘째, 실패 메시지는 반드시 영속 저장소(JMS 큐 또는 Data Store)에 남깁니다. 셋째, 무한 재시도로 시스템을 괴롭히지 않도록 재시도 상한과 격리 기준을 둡니다. 이 세 요소가 갖춰져야 비로소 "메시지 유실 없는 통합"이라고 말할 수 있습니다.
3. SAP Integration Suite의 에러 핸들링 아키텍처
SAP Integration Suite(멀티테넌트 클라우드 에디션)에서 Dead Letter 패턴을 구성할 때 사용하는 구성 요소는 다음과 같습니다.
| 구성 요소 | 역할 |
|---|---|
| Exception Subprocess | iFlow 내부에서 발생한 예외를 가로채는 서브프로세스 |
| JMS Adapter (Sender/Receiver) | 테넌트 내장 메시지 브로커의 큐에 메시지 저장/소비. Enterprise 에디션 또는 별도 메시징 자원 활성화 필요 |
| Data Store | JMS를 쓸 수 없는 경우의 대안 영속 저장소 |
| Escalation / Error End Event | 메시지 처리 상태를 Escalated 또는 Failed로 종료 |
| Retry Handling (JMS Sender) | 재시도 간격, 지수 백오프, Dead-Letter 설정 제공 |
주의할 점은 JMS 어댑터의 자체 "Dead-Letter Queue" 옵션은 브로커 장애 상황(메시지가 2회 이상 브로커 문제로 처리 불능일 때)을 다루는 기능이라는 것입니다. 업무 로직 실패(수신 시스템 오류 등)에 대한 Dead Letter 처리는 Exception Subprocess + 별도 JMS 큐 조합으로 직접 설계하는 것이 일반적으로 권장됩니다. 또한 JMS 큐 개수와 저장 용량은 테넌트 라이선스에 따라 제한되므로 사전에 Capacity를 확인해야 합니다.
4. 실전 예제 1단계: Exception Subprocess 설정
시나리오는 "웹샵 판매오더를 받아 S/4HANA OData API로 전송하는 iFlow"입니다. 먼저 처리 iFlow의 Integration Process 내부에 Exception Subprocess를 추가합니다. 팔레트에서 Process > Exception Subprocess를 끌어다 놓으면, 해당 프로세스 안에서 발생하는 모든 예외가 이곳으로 라우팅됩니다.
Exception Subprocess 안에 Groovy Script 스텝을 넣어 에러 정보와 원본 페이로드를 보존합니다.
import com.sap.gateway.ip.core.customdev.util.Message
def Message captureError(Message message) {
def map = message.getProperties()
def ex = map.get("CamelExceptionCaught")
if (ex != null) {
message.setProperty("errorType", ex.getClass().getCanonicalName())
message.setProperty("errorText", ex.getMessage() ?: "unknown")
}
def body = message.getBody(String) ?: ""
def mpl = messageLogFactory.getMessageLog(message)
if (mpl != null) {
mpl.setStringProperty("SalesOrderId",
map.get("salesOrderId") ?: "N/A")
mpl.addAttachmentAsString("FailedPayload", body, "application/json")
}
return message
}
포인트는 두 가지입니다. 예외 객체는 Exchange Property CamelExceptionCaught에서 꺼내며, 원본 페이로드는 Message Processing Log(MPL) 첨부로 남겨 운영자가 나중에 확인할 수 있게 합니다. 이 스크립트 뒤에서 Dead Letter 큐로 메시지를 보내게 됩니다.
5. 실전 예제 2단계: JMS Dead Letter Queue 구성
이제 실패 메시지를 담을 전용 큐를 만듭니다. Exception Subprocess의 마지막에 Receiver로 연결하고 JMS Receiver Adapter를 설정합니다.
Queue Name : DLQ_SALESORDER
Transaction Handling : Required for JMS
큐에 넣기 전에 Content Modifier로 재처리에 필요한 메타데이터를 JMS 헤더로 실어 보내는 것이 중요합니다.
SAP_JMS_Header_orderId : ${property.salesOrderId}
SAP_JMS_Header_errorText : ${property.errorText}
SAP_JMS_Header_failedAt : ${date:now:yyyy-MM-dd'T'HH:mm:ss}
SAP_JMS_Header_sourceIflow: SalesOrder_to_S4
입구 iFlow(송신 시스템 → 처리 큐)와 처리 iFlow(큐 → S/4HANA)를 분리하는 구조를 함께 적용합니다. 입구 iFlow는 검증만 하고 Q_SALESORDER_IN 큐에 적재 후 즉시 200을 응답합니다. 이렇게 하면 수신 시스템이 죽어 있어도 송신 측은 영향을 받지 않고, 메시지는 브로커에 안전하게 영속화됩니다. JMS 트랜잭션 핸들링을 "Required for JMS"로 두면 큐 적재 실패 시 롤백되어 부분 처리도 방지됩니다.
6. 실전 예제 3단계: 재처리(Retry) 메커니즘 구현
JMS Sender Adapter는 자체 재시도 기능을 제공합니다. 처리 iFlow의 JMS Sender에서 다음과 같이 설정합니다.
Queue Name : Q_SALESORDER_IN
Retry Interval (min) : 1
Exponential Backoff : 활성화
Maximum Retry Interval : 60
Dead-Letter Queue : 비활성화 (업무 실패는 직접 제어)
"n회 초과 시 Dead Letter로 격리" 로직은 Router로 분기합니다. JMS Sender가 제공하는 SAPJMSRetries 헤더를 사용합니다.
Route "재시도 초과 → DLQ" : ${header.SAPJMSRetries} > '5'
Route "정상 처리" (Default)
재시도 초과 경로는 DLQ_SALESORDER에 적재하고 Escalation End Event로 종료합니다. Escalation으로 끝내면 모니터링에서 "Escalated" 상태로 구분되어, 무한 재시도 중인 메시지와 격리 완료된 메시지를 한눈에 나눌 수 있습니다. DLQ 재처리용 iFlow는 수동 배포 또는 ProcessDirect 방식으로 노출해 운영자가 원인 해소 후 명시적으로 실행하도록 설계하는 것이 권장됩니다.
7. 운영 환경에서의 모니터링과 알림 설정
Dead Letter 큐는 "쌓이는지 아무도 모르면" 의미가 없습니다. 세 가지 층위로 관측을 구성합니다.
- Queue 모니터링: Integration Suite의 Monitor > Manage Stores > Message Queues에서 큐별 적재 건수와 용량을 확인합니다. DLQ에 1건이라도 있으면 조치 대상입니다.
- Alert Notification 연동: SAP Alert Notification Service를 구독하고, Escalated/Failed MPL 이벤트를 이메일이나 Slack/Teams Webhook으로 전달하도록 구성합니다.
- OData API 폴링: 별도 감시 iFlow에서 Cloud Integration의 MPL OData API를 주기 호출해 상태를 집계할 수 있습니다.
GET /api/v1/MessageProcessingLogs?$filter=Status eq 'ESCALATED'
and LogEnd gt datetime'2026-07-29T00:00:00'&$select=MessageGuid,
IntegrationFlowName,LogEnd&$format=json
4단계에서 MPL Custom Header(SalesOrderId)를 심어 두었기 때문에, 운영자는 어떤 오더가 실패했는지 비즈니스 키 기준으로 즉시 검색할 수 있습니다. 페이로드 첨부에는 개인정보가 포함될 수 있으므로 로그 보존 기간과 접근 권한(Role: MonitoringDataRead 등)을 함께 검토해야 합니다.
8. Dead Letter 패턴 적용 시 주의사항과 Best Practice
실무에서 자주 나오는 질문과 함정을 정리합니다.
- Q1. JMS가 없는 Basic 에디션인데 어떻게 하나요? — Data Store Write로 대체할 수 있습니다. 다만 Data Store는 큐잉 시맨틱이 약하므로 Select/Delete 순서를 직접 제어해야 하고, 보존 기간 만료 시 삭제된다는 점을 감안해야 합니다.
- Q2. 재시도 중 메시지 순서가 꼬이지 않나요? — 꼬일 수 있습니다. 순서 보장이 필요하면 수신 측을 멱등(idempotent)하게 설계하는 편이 안전합니다. 판매오더처럼 키가 있는 데이터는 수신 측 upsert로 중복 전송을 흡수하는 것이 일반적입니다.
- Q3. Exception Subprocess 안에서 또 에러가 나면? — 그 메시지는 Failed로 종료되고 DLQ에도 못 들어갑니다. Exception Subprocess 내부는 외부 호출 없이 최대한 단순하게(스크립트 + JMS 적재만) 유지하는 것이 권장됩니다.
- 독성 메시지(poison message) 주의: 페이로드 자체가 잘못된 메시지는 몇 번을 재시도해도 실패합니다. 재시도 상한(예제의 5회)을 반드시 두고, 매핑 오류 계열은 재시도 없이 즉시 DLQ로 보내는 Router 분기를 추가하면 자원 낭비를 줄일 수 있습니다.
- 트랜잭션 범위: JMS 트랜잭션은 하나의 iFlow 프로세스 범위에서만 유효합니다. JMS와 Data Store를 한 트랜잭션으로 묶을 수 없는 제약도 설계 시 확인해야 합니다.
이 패턴이 익숙해지면 Idempotent Process Call을 이용한 중복 제거, XI 어댑터의 EO(Exactly Once) 품질 보장, SAP Event Mesh와 연계한 이벤트 기반 재처리로 확장해 볼 수 있습니다.
댓글 0
아직 댓글이 없습니다.