공부내용공유

FCM 기능 구현 및 리팩토링을 하면서의 고민들 본문

Spring/Spring

FCM 기능 구현 및 리팩토링을 하면서의 고민들

forfun 2023. 9. 8. 10:17

서론


지금 진행중인 프로젝트에서 강의가 등록되었을때, 매니저가 공지사항을 등록했을때, 강의에 선정되었을때 등등 메인 비즈니스 로직에 알람기능은 필수이다.

 

원래 알람 기능을 맡았던 팀원과 프론트분과 기능을 구현하면서 어려움을 겪고 조금 진행이 늦어지고 있었는데 알람을 담당하던 팀원이 개인 사정으로 인해 프로젝트에서 하차하게 되었고 나와 다른 팀원 1명이서 임시방편으로 기능이 작동하게 고치고 베타 테스팅을 진행하였다.

 

그 후 FCM 도메인 공부 및 레퍼런스를 찾아보고 기능 수정, 추가 및 리팩토링이 필요하다고 판단을 내렸고 해당 issue 를 내가 담당하게 되었다. 

도메인 공부 및 리팩토링을 하면서 고민했던것들, 작성한 코드등을 정리하기 위해 이 글을 작성하였다.

 

 

본론


일단 기능 수정 및 리팩토링에 앞서 현재 어플리케이션의 요구사항을 한번 정리해 보았다.

알림 기능 요구사항

  • 읽음 여부 처리
  • 날짜 , 시간 , 제목, 내용 , 링크(공지 상세 페이지 or 강의 상세 페이지)
  • 개인 알림 서랍
  • 알림 전체 전송
  • 강사 선정시 알림 자동 전송
  • 공지 등록시 알림 자동 전송
  • 알림 선택시 해당 페이지로 이동 (version 2)  (json 메세지에 link 필드 추가 , 프론트에서 해당 link 로 로직 생성)
  • 알림 종류별 수신 여부 설정 (version 2)

토큰 기능 요구사항

  • 한 계정에 여러기기 등록 가능 (여러 토큰 등록 가능)
  • 로그인, 로그아웃시 토근 갱신

도메인 구조

기획상 요구사항은 이정도였고 version 2 는 지금 당장 해결해야할 문제는 아니고 일단 기본 기능을 먼저 끝내고 그 다음 구현할 사항이다.

해당 요구사항을 위해 도메인 설계는 이렇게 구성하였다.

  • userNotification 을 통해 개인별 알림읽음, 알림서랍 조회 기능을 구현.
  • token 을 1:N 으로 만들어 한 계정에서 여러 기기 알림 관리.

 

 

기능 설계 및 고민한 점

지금부터는 리팩토링, 기능 수정을 하면서 어떤 고민을 했고 어떤식으로 설계했는지 코드 예시와 설명을 작성할 예정이다.

기능분리

기존 코드에는 알림 전송을 담당하는 notificationService 에

FCM key 를 이용한 인증, Andorid,Apns config 생성, 알림 전송 , 알림 관련 CRUD 로직들이 전부 들어가 있었다.

이는 SRP, OCP 등을 위배하여 코드의 간결성, 유지보수성을 떨어트리기에 각 기능들을 분리하였다.

 

  • FCM Autorization , config  -  FirebaseMessagingInstance Bean 으로 등록

 

 

  • NotificationService - 알림 전송, 알림 관리

 

 

  • UserNotificationService - 유저별 알림 관리

 

 

  • Notification Req - 기본 Apns, Andorid config 관리

 

Topic 및 Token 관리

현재 요구사항은

  • 매니저가 알림을 직접 모든 유저에게 전송하는 기능
  • 강사 선정시 개별 유저에게 알림 전송
  • 공지 등록시 모든 유저에게 알림 전체 전송

이 있고 알림을 끄게되면 이 모든 알림들이 무시된다.

하지만 version 2 요구사항에 알림 종류별 수신 여부 결정 기능이 논의된적이 있고 이를 고려하여 어떤식으로 설계를 할지 고민을 하였다.

 

기존 알림 전체 전송은 각 사람의 token 들을 불러와 1명씩 알림을 전송하는 식이였고

이는 network I/O 가 클거같아 다른 대안들을 알아보았는데

  • sendMulticast
  • Topic
  • sendAll

정도가 있다. sendMulticast 나 sendAll 의 경우 모든 유저 리스트를 불러와 해당 유저의 token 여부 혹은 active 여부를 판단으로 token 리스트를 만들고 해당 리스트에 대해 전체 전송을 하는 식으로 구현하게 된다.

 

추후 알림 종류별 알림 수신 여부 기능, DB에서 모든 user 를 불러오는 구현 방식을 생각했을 때 topic 을 통한 관리가 더 효율적이라 생각하여 유저가 로그인 하게되면 기본적으로 All 이라는 topic 을 구독, 전체 전송 메세지는 Topic 에 대한 전송으로 해결했다.

 

  • (정정) 각 유저마다 알림을 저장해야 하므로 어자피 모든 유저를 같은 트랜잭션 안에서 불러야 하기 때문에 이부분에서 성능 차이는 크게 없을거 같다.

 

요구사항 관련 토의를 할때 나왔던 알림 타입별 수신여부 결정 기능은 나중에 Topic 을 All 뿐만 아닌 각 알림 타입별로 나누어 관리를 하여 구현할 것이다.

 

  • Topic 으로 관리할 때 남아있는 의문점은 만약 user 가 어플을 지우면 FCM 서버에서 자동으로 token 을 topic 으로부터 삭제할까? 이다. 
    • fcm chat 에서 물어봤지만 답변이 아직 없다.
    • 또한 token 을 새로 받는다고 무조건 다른 token 이 아니라 같은 token 이 나오는 경우가 빈번해 아직 테스트를 못해봤다.
    • 현재는 로그아웃시 혹은 토큰 갱신시 구독을 먼저 없애고 토큰을 제거해주는 로직이지만 FCM 의 처리 방식에 따라 topic 관련 로직을 수정해야 한다.

https://stackoverflow.com/questions/54471961/will-deleting-an-fcm-token-also-unsubscribe-it-from-an-fcm-topic

FCM 내에서 자동으로 감지하고 token 을 지우고 token 이 삭제되면 어자피 알림은 안가기 때문에 topic 을 사용하게 되면 확실히 관리 측면에서 이점이 있는것 같다.

 

 

 

결론


각 계층과 도메인에 대한 의존성 고민도 했지만 일단 기능 완성이 먼저라 이러한 식으로 안되는 기능들을 수정하고 구조를 바꾸면서 리팩토링 작업을 완료하였다.

추후 팀원과 의논후에 FCM 예외처리, token 및 topic 수명 관리, 기능 고도화 등의 작업을 진행할 예정이다.