개발 slecs

연락처 송금 파싱 재시도·매칭 누락 버그 수정

목차

연락처 송금은 구조 자체가 조금 특이하다. 결제 흐름의 끝단에서 은행 앱 화면을 Playwright로 직접 조작해 입금 처리를 완료하는 방식인데, 은행마다 UI가 달라서 핸들러를 각각 따로 유지하고 있다. 브라우저 자동화 기반인 만큼 화면 텍스트를 파싱해서 완료 여부를 판단해야 하고, 그 판단이 틀리면 조용히 오동작한다. 이번 수정은 그 조용한 오동작들을 하나씩 잡은 작업이었다.

이번에 수정한 네 가지

수정 사항이 네 개라고 쓰면 작게 보이지만, 각각 독립적인 원인으로 발생한 버그들이었다.

은행 셀렉터 감지 로직 오류는 특정 은행 핸들러에서 DOM 셀렉터를 잘못 특정하고 있었던 문제다. 은행 앱 UI가 업데이트되면서 셀렉터가 바뀌었는데 핸들러가 그걸 못 따라간 케이스. 이건 Playwright 기반 자동화에서 반복적으로 생기는 문제인데, 셀렉터를 하드코딩해두면 앱 버전이 올라갈 때마다 조용히 죽는다.

계좌 로테이션 순서 문제는 여러 계좌를 순환하면서 처리할 때 순서가 어긋나는 버그였다. 특정 계좌가 처리 중 상태인데도 다음 요청이 같은 계좌로 붙는 케이스가 생겼고, 그게 중복 처리 위험으로 이어질 수 있었다.

파싱 실패 후 재시도 필터 조건 누락은 이번 수정의 핵심이다. 파싱이 실패했을 때 재시도 큐에 올리는 로직이 있는데, 재시도 대상을 걸러내는 필터에 sysId 조건이 빠져 있었다. 결과적으로 특정 sysId에 해당하는 건이 필터를 통과하지 못하고 재시도 없이 드롭됐다.

비회원 주문 매칭 누락은 매칭 로직에서 비회원 주문을 정상 주문과 다르게 다루는 분기가 없어서 발생했다. 회원 주문 기준으로만 조회 조건이 걸려 있다 보니 비회원 케이스에서 NO_MATCH가 반환됐다.


완료 감지는 정규식이 1차 방어선이고, 거기서 못 잡으면 Claude API에 화면 텍스트를 넘기는 AI 폴백 구조다.

// 완료 감지 regex 통합 패턴
private static final Pattern COMPLETE_PATTERN =
    Pattern.compile("(이체|송금|완료|처리됐|성공)");

문구는 은행마다 조금씩 다르다. "이체가 완료됐습니다", "송금 처리가 성공했습니다", "처리됐습니다" 등 변형이 많아서 패턴에 다 때려박는 방식인데, 그래도 못 잡히는 엣지 케이스가 나온다. 그래서 regex 실패 시 화면 전체 텍스트를 AI에 넘겨서 "완료됐냐 아니냐"를 판단받는 구조를 붙여뒀다. 정확도는 올라가는데 API 비용과 레이턴시가 붙는 트레이드오프가 있어서, 어디까지나 폴백으로만 쓴다.

셀렉터 안정성을 어떻게 유지하느냐

Playwright로 은행 UI를 자동화할 때 가장 골치 아픈 게 셀렉터 깨짐이다. 앱 업데이트 주기가 은행마다 다르고, 업데이트 직후에 핸들러가 동작을 멈추면 해당 은행 채널이 통째로 멈추는 것처럼 보인다.

지금 구조는 성공한 셀렉터를 DB에 캐싱해두고 재활용하는 방식이다.

  1. 저장된 셀렉터로 먼저 시도
  2. 실패하면 전체 탐색(fallback scan)으로 넘어감
  3. 전체 탐색에서 성공한 셀렉터를 DB에 갱신

이걸 "자가학습 캐시"라고 부르는데, 은행 앱이 업데이트되더라도 최초 한 번만 전체 탐색이 돌고, 이후 요청부터는 갱신된 셀렉터를 바로 쓴다. 핸들러 코드를 건드리지 않아도 어느 정도 자동으로 적응하는 셈이다.

처리 상태는 네 가지로 관리한다.

상태 의미
PENDING 처리 진행 중
SUCCESS 완료
NO_MATCH 주문 매칭 실패 - 재시도 큐로
MANUAL_REQUIRED 자동 처리 불가 - 수동 처리

NO_MATCH는 매칭 실패지 처리 실패가 아니라서 재시도가 의미 있다. 반면 MANUAL_REQUIRED는 자동화로 해결이 안 되는 케이스라고 판단된 건이어서 운영팀 큐로 넘긴다. 이 구분이 명확해야 재시도 큐가 불필요하게 쌓이지 않는다.

이번 sysId 필터 누락은 딱 이 경계에서 생긴 버그였다. 재시도 대상이어야 할 건이 필터를 통과 못 해서 MANUAL_REQUIRED처럼 방치됐던 것. 실제로는 자동 처리가 가능한 건인데 수동 처리 큐에 쌓이면 운영 비용이 올라간다. 수정 자체는 간단했지만 영향 범위가 넓었다.

브라우저 자동화 기반 결제 연동은 외부 UI에 의존하는 특성상 깨질 포인트가 많다. 그걸 감안해서 폴백 레이어를 여러 겹 두는 게 지금 전략인데, 이번 작업은 그 폴백 레이어 중 하나가 조건 오류로 제대로 동작하지 않던 걸 고친 거다. 작은 수정이지만 재시도 누락이 쌓이면 운영 쪽에서 티가 나기 시작하는 종류의 버그라서 빠르게 잡은 게 맞다고 본다.

댓글 0

첫 댓글 달아줘.