사이드 프로젝트

사이드 프로젝트 수행기 (2)

wangkisa 2022. 6. 12. 18:06

이번에 진행했던 부분은

 

어드민 서버에서 지정된 조건의 유저들에게 

푸시 서버로 API 를 호출하면

푸시 서버에서 해당 API를 받아서 단말기로 푸시를 보내는 기능을 구현하였다.

(소스레벨에서는 어드민 모듈과 푸시 모듈로 구성)

 

푸시 보내는 어드민 화면은 다음과 같다. 

 

 

 

푸시 서버는 별도로 구현하였고,

여기서는 위 화면의 '푸시 종류' 중에서 여러 종류 중 '이벤트 전체 알림' 인 경우에 대해 진행하였다.

 

 

푸시 서버에서 이벤트 푸시 보내는 경우 내용 소스이다.

// 해당 이벤트 존재하는지 체크
Event event = eventService.findById(requestDTO.getEventId());

List<User> allEventUsers = userService.findAllForEvent();
int successCnt = 0;
int failCnt = 0;
Exception exception = null;
for (User user : allEventUsers) {
    
    try {
        if (user.getProfile().isPushEvent() && user.getProfile().getUserOs() != null && user.getProfile().getUserOs().equals(UserOS.AOS)) {
            boolean isResult = firebaseCloudMessageService.sendPushMessage(user.getPushToken(),
                    requestDTO.getTitle(), requestDTO.getPushContent(),
                    PushType.EVENT_ALL_USER, requestDTO.getEventId());

            if (isResult) {
                successCnt += 1;
            }
            else {
                failCnt += 1;
            }

            Thread.sleep(300);
        }

    } catch (IOException e) {
        failCnt += 1;
        throw new RuntimeException(e);
    } catch (InterruptedException e) {
        failCnt += 1;
        throw new RuntimeException(e);
    } catch (Exception e) {
        failCnt += 1;
        throw new RuntimeException(e);
    }

}
pushHistoryService.updatePushHistory(requestDTO.getPushHistoryId(),
        successCnt, failCnt);

if (failCnt > 0) {
    throw new RuntimeException(exception);
}

 

처음에 대충 이런식으로 개발 진행했었는데,

동작은 하긴 했지만 보다보니 문제가 좀 보이던게 

 

} catch (IOException e) {
    failCnt += 1;
    throw new RuntimeException(e);
} catch (InterruptedException e) {
    failCnt += 1;
    throw new RuntimeException(e);
} catch (Exception e) {
    failCnt += 1;
    throw new RuntimeException(e);
}

 

이 부분에 관한 내용이었다.

에러가 발생하게 되면  이 부분에서 문제가 발생하게 될 것인데,

boolean isResult = firebaseCloudMessageService.sendPushMessage(user.getPushToken(),
        requestDTO.getTitle(), requestDTO.getPushContent(),
        PushType.EVENT_ALL_USER, requestDTO.getEventId());

위처럼 처리를 하게 되면 

문제 발생시  throw new RuntimeException(e); 로 처리하게 되어 

 failCnt += 1; 연산은 필요가 없어지게 되어 매번 해당 블락에서

불필요하게 pushHistoryService.updatePushHistory() 로 호출하게 되는 문제가 생길 수가 있다.

 

그래서, 생각해낸 방법은 

} catch (IOException e) {
    failCnt += 1;
    exception = e;
} catch (InterruptedException e) {
    failCnt += 1;
    exception = e;
} catch (Exception e) {
    failCnt += 1;
    exception = e;
}

처럼 Exception exception = null; 로  초기화해주고, 

에러가 발생한 곳에서 실패 카운트를 + 1 해주고, 

어떤 에러인지 파악하기 위한 부분은 exception = e; 로 받아서 

 

해당 로직이 끝난 뒤,

pushHistoryService.updatePushHistory(requestDTO.getPushHistoryId(),
                successCnt, failCnt);

if (failCnt > 0) {
    throw new RuntimeException(exception);
}

해당 푸시 히스토리 값의 성공과 실패 카운트를 업데이트 해준뒤,

실패 카운트가 있는 경우 결과에서 알려주도록 처리하도록 하였다.

 

 

* 아직은 유저가 많은 경우에 푸시를 보내는 부분에 대한 처리가 없는 상태인데,

향후에는 스프링에서 제공하는 비동기 메시지 방법이나 카프카 같은걸 사용해서 처리가 필요할 것 같다.