외부에서 상품 정보를 받아 오는 기능을 만들었다. 잘 도는데 어떤 상품은 이름이 비어 있었다.
Table of contents
Open Table of contents
성공만 보고 있었다
Apache HttpClient 로 받아 HTTP 200 이면 MySQL 에 넣는 구조였다. 그런데 200 이면서 내용이 빈 경우가 있었다.
<response>
<result>SUCCESS</result>
<product></product>
</response>
상대 쪽에서 없는 상품을 물으면 이렇게 준다. 성공이라고 오고 안이 비어 있다.
DOM 파서도 조용히 넘어갔다. 빈 요소에서 getTextContent() 는 null 이 아니라 빈 문자열을 돌려준다. 그대로 INSERT 된다. 응답이 성공이라는 것과 내용이 있다는 것은 다른 얘기였다.
세 가지를 나눠서 봤다
확인할 것이 셋이라는 것을 그때 알았다. 붙었는지, 상대가 성공이라고 했는지, 필요한 값이 들어 있는지다.
if (res.getStatusLine().getStatusCode() != 200) { ... } // 1) 붙었나
if (!"SUCCESS".equals(getTagValue(body, "result"))) { ... } // 2) 성공이라 했나
if (name == null || name.trim().length() == 0) { ... } // 3) 값이 있나
셋이 서로 다른 층이다. 하나만 보면 나머지 둘을 놓친다. 처음에는 첫 번째만 보고 있었다.
배치가 멈추지 않게 했다
값이 없을 때 전부 예외로 던지면 배치가 중간에 멈춘다. 종류를 나눴다.
상품 코드와 이름처럼 꼭 있어야 하는 것이 없으면 그 건을 건너뛰고 목록에 남긴다. 설명이나 이미지처럼 없어도 되는 것은 비워 두고 넘어간다.
} catch (ApiException e) {
logger.warn("건너뜀 code=" + code + " : " + e.getMessage());
skipped.add(code);
}
배치는 끝까지 돌고 건너뛴 것이 목록으로 남는다. 끝나고 성공과 건너뜀을 log4j 에 숫자로 찍게 했다. 완료라고만 찍으면 몇 건이 빠졌는지 모른다.
2011-10-20 성공 1,240건, 건너뜀 3건
2011-10-21 성공 1,238건, 건너뜀 5건
2011-10-22 성공 890건, 건너뜀 353건
숫자가 남으니 어제와 비교할 수 있다. 갑자기 바뀌면 내 쪽이 아니라 상대 쪽이 바뀐 것이다.
다시 해도 안 되는 것
이미 이름 없이 들어간 것이 412건이었다. 그 목록으로 다시 받아 오니 380건은 채워지고 32건은 여전히 비었다. 상대 쪽에도 없는 상품이었다.
MySQL 에 다시 해도 안 되는 것을 표시해 뒀다. 안 하면 매번 그 32건을 계속 시도한다.
HttpConnectionParams 로 시간 제한도 넣었다. 응답이 늦으면 배치가 멈춰 있었는데 제한이 없었다. ConnectionTimeout 과 SoTimeout 을 따로 준다. 하나만 주면 붙고 나서 응답이 안 오는 경우에 계속 기다린다. 제한을 넣으니 하루 걸리던 배치가 40분에 끝났다. 느린 몇 건이 전체를 잡고 있었던 것이다.
정리
- 응답 성공과 내용이 있다는 것은 다르다. 성공이면서 비어 있을 수 있다
- 붙었는지와 상대가 성공이라 했는지와 값이 들어 있는지를 나눠서 본다
getTextContent()는 빈 요소에서 예외가 아니라 빈 문자열을 준다- 꼭 있어야 하는 것과 없어도 되는 것을 가른다
- 전부 예외로 하면 배치가 중간에 멈춘다
- 끝나고 숫자를 남긴다. 어제와 비교하면 내 쪽인지 상대 쪽인지 갈린다
- 이미 들어간 빈 값을 찾아 다시 받는다
- 다시 해도 안 되는 것을 표시한다. 안 하면 매번 같은 것을 시도한다
- 시간 제한은
ConnectionTimeout과SoTimeout을 따로 준다