# 콜드메일 워크플로우 interrupt() 패턴 수정 계획 **작성일**: 2026-01-21 **완료일**: 2026-01-21 **관련 파일**: `rb8001/app/services/workflows/coldmail_workflow.py`, `rb8001/app/services/slack/coldmail_service.py` → **구현 완료**: `troubleshooting/260121_coldmail_interrupt_state_preservation_fix.md` --- ## 문제 상황 - `process_node`에서 `interrupt()` 호출 후에도 워크플로우가 `send_node`까지 진행 완료 - `waiting_confirmation`이 비워진 상태로 checkpoint 저장 - 사용자가 Slack 버튼 클릭 시 `Email not found in waiting_confirmation` 에러 발생 **근본 원인**: `interrupt()` 반환값을 사용하지 않고, 별도 라우팅으로 `confirm_node` 분기 시도 **히스토리**: - 2025-12-23: `interrupt_after=["process"]` 사용 → process 노드 완료 후 중단 시도 - 2026-01-18: LangGraph 1.0 업그레이드 시 `interrupt()` 동적 호출로 변경 - **누락된 부분**: `decision = interrupt(payload)` 후 `decision`으로 분기하는 패턴 미적용 --- ## 아키텍처 ### 현재 (잘못된 패턴) ``` process_node → interrupt() 호출 → 워크플로우 계속 진행 → send_node → END ↑ waiting_confirmation 비워짐 ``` ### 수정 후 (올바른 패턴) ``` process_node → interrupt(payload) → 워크플로우 일시정지 ↓ 사용자 버튼 클릭 ↓ Command(resume={"confirmed": True, "email_id": ...}) ↓ interrupt() 반환값으로 결과 수신 → 후속 처리 ``` --- ## 필요 작업 ### Phase 1: process_node 수정 - `coldmail_workflow.py:106-157`: `interrupt()` 반환값 패턴 적용 - `decision = interrupt({"emails": waiting_confirmation})` 형태로 변경 - `decision`에서 `confirmed_email_id` 추출하여 처리 - `interrupt()` 이후 코드가 재개 시점에 실행되도록 구조 변경 ### Phase 2: coldmail_service.py 수정 - `coldmail_service.py:160`: `Command(resume=...)` 호출 시 사용자 입력 전달 - `Command(resume={"confirmed": True, "email_id": email_id})` 형태로 변경 ### Phase 3: confirm_node 제거 또는 통합 - `route_after_process` 분기 로직 제거 - `confirm_node` 로직을 `process_node` 내부로 통합 (interrupt 반환값 처리) --- ## 검증 방법 - 신뢰도 95% 미만 이메일 → Slack 버튼 전송 확인 - 버튼 클릭 후 `Command(resume=...)` → 워크플로우 재개 확인 - `waiting_confirmation` 상태 유지 및 정상 처리 확인