
post vs get 시리즈에서의 첫 게시물에서는 화면단에서의 단순한 호출이었지만
이번에는 자바로 RestTemplate을 사용하여 JSON데이터를 담아 post방식의 호출 경험을 적어보려한다.
해당 업무는 A라는 고객사에서 고객사 사이트에 로그인 할때마다 사원번호를 가지고 B라는 사이트에서의 데이터를 조회 후 화면에 리턴하는 방식이였다.
(이후 엄청난 나비효과를 가져올 예정,,)
필수 조건은 다음과 같았다.
1) 3년치 데이터를 조회할것
2) 연동오류 및 기타 error에 대한 예외처리 진행할것
(연동오류시 다음 트랜잭션이 막혀 UI에서 다음 트랜잭션들의 데이터들이 보이지 않아 사용자가 보기에 error라고 판단 가능성 있으므로)
사실 2번에 대한 예외처리 사항은 다른 업무에 영향을 미치지 않기 위해 개발자라면 반드시 챙겨할 부분이라고 생각한다.
최소한의 logger 처리라도,,
내가 작성한 로직의 큰 틀은
for문으로 3년치 데이터를 조회할건데 그안에 json객체를 붙인후 호출할 예정이다.
작성한 코드는 아래와 같다.
//메소드 실행
public List<Map<String, Object>> getPoint(Map<String, Object> param) {
//호출된 바디 담을 변수
String received;
//조회 데이터를 담을 리스트
List responseData = new ArrayList();
//year
LocalDate now = LocalDate.now();
int year = now.getYear();
//반복문 시작(3번)
for (int i = 2; i >= 0 ; i--) {
//만들어놓은 리스트에 조회된 데이터를 맵에 넣어 한줄씩 추가할 예정
Map row = null;
try {
//Content Type 헤더를 Application/json 으로 설정
HttpHeaders headers=new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// JSON 객체 선언
JSONObject parameter = new JSONObject();
//화면에서받은 파라미터(년도,ID)를 선언한 JSON에 넣기
parameter.put("searchYear",String.valueOf(year-i));
parameter.put("searchId", sessionUserInfo.getEMPL_NUMB());
//데이터가 담긴 json을 hhtp객체에 담아 요청
HttpEntity<String> req = new HttpEntity<>(parameter.toJSONString(), headers);
RestTemplate client=new RestTemplate();
ResponseEntity<String> responseEntity =client.postForEntity("http://ssyenc.ysunkorea.com/api/support/", req, String.class);
//logger로 상태 중간 점검(혹시 error일 경우 code확인용ㅎ)
logger.info("API call finish. Received data from api...");
logger.info("--- data ResponseEntity : {}", responseEntity);
// API 호출 수신 값
received = responseEntity.getBody();
//호출 바디 확인
logger.info("Received Data : {}", received);
//String으로 되어져있는 바디부분을 다시 JSON형태로 파싱
JSONParser parser = new JSONParser();
JSONObject data = (JSONObject) parser.parse(received);
//파싱된 JSON에서 data키값으로 get
JSONArray detail = (JSONArray) data.get("data");
//위에서 선언한 맵에 추가
row = new HashMap();
//code값이 4000일경우 예외처리
if (data.get("code").equals("4000")) throw new ProcessException(data.get("code") + " : " + data.get("message"));
JSONObject result = (JSONObject) detail.get(0);
JSONObject support = (JSONObject) ((JSONArray)result.get("support")).get(0);
// 응답받은 데이터가 있을경우 메인화면쪽으로 return해주고 연결이 안되거나 데이터가 제대로 오지 않았을 경우는 0으로 채워서 화면에 전송
//받아온 data 맵에 추가
//map의 경우 key가 겹칠때 value가 덮어쓰기 되므로 확인 필수!
row.put("syear", support.get("syear"));
row.put("total", support.get("total"));
row.put("use", support.get("use"));
row.put("remain", support.get("remain"));
//파싱실패 했을때 예외처리
} catch (ParseException e) {
// TODO Auto-generated catch block
logger.info("포인트 Parse 실패");
row.put("syear", String.valueOf(year-i));
row.put("total", 0);
row.put("use", 0);
row.put("remain", 0);
//예외처리
} catch (Exception e) {
// TODO Auto-generated catch block
logger.info("포인트 연동 오류 :: " + e.getMessage());
row.put("syear", String.valueOf(year-i));
row.put("total", 0);
row.put("use", 0);
row.put("remain", 0);
} finally {
//위에서 선언한 리스트에 방금 넣은 맵 추가
responseData.add(row);
}
}
//api종료!
logger.info("--- API call end.");
//데이터가 담긴 리스트 반환
return responseData;
}
대용량 트래픽폭주에 대한 경험 부족
이부분은 정말 생각도 못한 부분이었다.
서버를 오픈한 첫날 내가 담당한 부분들의 트랜잭션이 꽉꽉 막혀 할일들을 못하고 쌓이기만했다.
생각만해도 끔찍,,
이유를 찾아보니 A라는 고객사 사이트에 로그인할 경우 B라는 사이트에 요청을 날리도록
코드를 작성했는데 이때 B라는 사이트에 갑자기 많은 트래픽이 한번에 몰리게 되니
처리 속도가 늦어지고 A고객사의 사이트도 데이터 처리가 늦어져 쓰레드들이 쌓이기만 했던것,,
출근시간에 직장인들이 한번에 A사이트에 로그인하니 B라는 사이트에도 똑같이 몰리게 되고 B라는 사이트에서의 서버가 그만큼 감당을 못하고 매우 느린 속도로 데이터를 뱉어낸것이다..
(나는 나의 was만 걷는다,,)
출근과 동시에 로그인하니 당연히 트래픽이 몰릴것이라고 왜 전혀 예상하지 못했을까,,ㅎㅎㅎㅎ
🔥오픈과 동시에 긴급 호출🔥
위와 같은 error를 해결하기위해 긴급배포를 돌렸는데
아래와 같이 코드를 수정하였다.
정답은
RestTemplate에 Timeout걸어주기!!!!!
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(10*1000); //(연결시 타임) 10초
//factory.setReadTimeout(10*1000); //(불러온 값 읽는 타임) 10초
RestTemplate client=new RestTemplate(factory);
불러들인 데이터는 길지 않아서 일단은 주석처리해놨다.(만일을 대비해 일단 주석으로 남기기ㅎ)
타임 아웃걸어주고 일정 시간지나면 예외처리로 빠지게 작성하였다.
피땀 눈물과 함께 이렇게 또 한가지 스킬과 예지력이 쌓였다.^____^