이 글은 제가 n8n에서 LLM 워크플로우를 프로덕션 환경에서 실행하는 과정을 공개적으로 기록하는 시리즈 중 일부입니다. 여기에 있는 모든 내용은 제가 판매하고 지원하는 실제 템플릿에서 가져온 것입니다. 실수한 부분은 저의 것이고, 수정된 부분은 테스트를 거쳤습니다.
워크플로우는 정상이었지만, 자격 증명(Credential)이 아니었다
제가 만든 하나의 워크플로우가 매시간 CRM에서 새로운 행을 가져와 LLM 호출로 데이터를 보강한 후 결과를 다시 기록하는 작업을 했습니다. 이 작업은 몇 달 동안 아무 문제 없이 실행되었습니다. 그러다 어느 토요일 아침, 쓰기(writing)를 멈췄습니다. 어떤 노드도 빨간색이 아니었습니다. 실행 로그에는 '성공'으로 표시되었는데, 이는 워크플로우의 오류 경로가 실패한 API 호출을 포착하고, 이를 기록하며, 다음 단계로 넘어갔기 때문입니다. 로그에는 작은 글씨로 401 Unauthorized라고 적혀 있었습니다.
OAuth 토큰이 만료된 것이었습니다. 리프레시 토큰(refresh token) 역시 몇 주 전에 조용히 만료되었는데, 제공업체는 해당 권한 부여(grant)에 대한 90일간의 비활성 상태가 지속되면 리프레시 토큰을 순환시키기 때문에 아무도 재인증(re-authorize)하지 않았던 것입니다. 워크플로우 자체가 실패한 것이 아니었습니다. 단지, 매번 '성공'하는 실행을 거치며, 예의 바르게 제 역할을 멈추었을 뿐입니다.
자격 증명 만료는 가장 조용한 프로덕션 장애 유형 중 하나입니다. 버그처럼 보이지 않습니다. 아무 일도 일어나지 않은 것처럼 보입니다. 그리고 항상 공휴일에 발생하는 것 같습니다. 왜냐하면 그때가 바로 아무도 대시보드를 지켜보고 있지 않기 때문입니다.
만료는 놀라움이 아니라 일정이다
해결책은 모든 자격 증명을 영구적인 사실(permanent fact)로 취급하는 것이 아니라, 알려진 만료일이 있는 무언가로 간주하는 것에서 시작합니다. 제 워크플로우가 의존하는 각 자격 증명에 대해 저는 세 가지를 한 곳에 기록합니다: 그것이 무엇인지, 언제 만료되는지(또는 언제 재인증해야 하는지), 그리고 누가 이를 재인증할 책임이 있는지입니다. 순환 리프레시 토큰을 사용하는 OAuth 권한 부여에는 교체 주기 2주 전에 달력 알림을 설정합니다. 고정된 만료일이 있는 API 키도 마찬가지입니다. 심지어 '만료되지 않는' 키라 할지라도, 제공업체가 아무런 통보 없이 정책을 변경하기 때문에 분기별 점검을 받습니다.
이 목록은 n8n 외부에서 존재합니다. 워크플로우가 제공자(provider)와 통신할 수 있게 해주는 자격 증명(credential)이 만료되었다면, 워크플로우 자체가 사용자에게 알려줄 수 없습니다. 즉, 같은 만료된 채널을 통해 도달할 방법이 없기 때문입니다. 이 만료 목록은 지루한 스프레드시트이지만, 저를 두 번이나 구해주었습니다.
“인증 실패(auth failed)”와 “요청 실패(request failed)” 분리하기
두 번째 해결책은 워크플로우 내부에 있습니다. 인증 실패가 일시적 실패(transient failure)와 같은 경로로 전파되는 것을 절대 허용해서는 안 됩니다. 429 또는 500 코드는 “나중에 다시 시도하라”는 의미입니다. 반면, 401 또는 403 코드는 “권한이 사라졌으니 재시도는 도움이 되지 않으며, 모든 재시도는 실제 문제를 가리는 헛된 작업이다”라는 의미입니다.
제가 사용하는 워크플로우에서는 외부 API와 통신하는 HTTP 노드 다음에 다른 어떤 일이 일어나기 전에 상태 코드(status code)를 확인하는 절차를 거칩니다. 인증 실패는 전용 분기(dedicated branch)로 이동합니다: 워크플로우를 중단시키고, 자격 증명과 제공자를 명시한 알림을 보내며, 실행 기록을 확실하게 실패로 표시합니다. 일시적 실패는 재시도 분기로 이동합니다. 규칙은 간단합니다. 재시도 루프가 인증 실패를 몇 시간 동안 처리하면서 성공했다고 보고해서는 안 됩니다.
이는 또한 제가 이전에 작성한 canary 기사의 오류 워크플로우 역시 그 차이를 알아야 한다는 것을 의미합니다. “워크플로우 실패”만으로는 충분하지 않습니다. 알림에는 “이 자격 증명에 대한 인증 실패(authentication failed for this credential)”라고 명시되어야 합니다. 왜냐하면 이 문장이 사람으로 하여 재실행 대신 재인증(re-authorize)을 하도록 유도하기 때문입니다.
재인증은 기억이 아닌 운영 매뉴얼(runbook)
세 번째 해결책은 기술적으로 가장 덜 복잡하지만, 가장 중요한 부분입니다. 재인증 과정은 다른 사람이 따라 할 수 있는 문서화된 절차여야 합니다. 어떤 계정이 권한을 소유하는지, 로그인 정보가 어디에 있는지, 필요한 범위(scope)는 무엇인지, 다운되었을 때 무엇이 고장 나는지, 그리고 정상으로 돌아왔는지 어떻게 검증하는지—모든 것을 만료되기 전에 문서로 작성해야 하며, 워크플로우가 침묵할 때 자정 무렵에 재구성해서는 안 됩니다.
내가 이 경험을 통해 배웠다: 토큰이 만료되었던 첫 번째 경우, 어떤 계정이 해당 권한 부여(grant)를 소유했는지 파악하는 데 한 시간을 썼는데, 이는 n8n의 자격 증명 이름이 "CRM Prod"였고 실제 로그인은 내가 거의 열어보지 않는 받은 편지함에 속해 있었기 때문이다. 이제는 자격 증명 이름에 소유 계정을 포함시키고, 운영 매뉴얼(runbook)에는 해당 받은 편지함을 명시한다. 지루하지만, 공휴일 서비스 중단 사태를 10분짜리 작업으로 바꾼다.
원칙 (The principle)
워크플로우는 코드만으로 실행되지 않는다. 그것들은 다른 시스템들이 부여한 권한(permissions)을 기반으로 실행되며, 모든 권한에는 만료 시점이 있다. 이 시간 흐름을 추적하고, 인증 실패를 일시적인 오류와 분리하며, 갱신 방법을 문서화하지 않으면, 당신의 자동화는 내재된 만료 날짜를 갖게 되며, 그날은 당신이 가장 원치 않는 날에 도착할 것이다.
저는 AI Automation Lab — 운영 환경에서 사용 가능한 n8n 워크플로우 템플릿을 제작하고 있습니다. 무료 AI Hook Generator는 제가 실제 워크플로우를 어떻게 구성하는지 보여주며, 저의 오픈 소스 템플릿은 github.com/zhp910318/n8n-ai-automation-lab에서 확인할 수 있습니다.