ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Batch에서 FCM 발송 오류 트러블슈팅
    Language/Java 2024. 9. 12. 11:24


    공지사항 및 푸시 발송 컨텐츠를 등록해두고 전송요청을 하게되면 배치에서 푸시를 받아야 할 대상건들을 추려내서 발송하는 형태로 서비스 중이었다. 그런데 한달쯤 전부터 푸시의 발송 실패건들이 늘기 시작했다. 푸시발송에 실패한 토큰들은 앱을 삭제하거나 거부하였을때 DB에서 물리적으로 삭제하도록 개발되어 있었는데 그러다 보니 매일 발송대상에 올라가는 푸시건수들이 실패한 건수만큼 줄기 시작하였다.. OTL..

     

    원인을 찾자!

     

    원인파악 및 트러블슈팅

    com.google.firebase.messaging.FirebaseMessagingException: Operation is not implemented, or supported, or enabled.

    다른 오류들도 있었지만 포인트는 저거였다. 구글링 해보니 10건 전송하면 7건 성공 3건 실패등 요청할때마다 성공/실패의 건수가 달라진다는 말들이 많았다.

     

     

    의심

    Firebase에서 온 레거시 서비스 종료 메일

    메일을 받은 당시 기억속으로 빠져들면 우리 버전이랑 무관한 것으로 결론 내리고 그당시에는 대응하지 않기로 하였다.

    Hi xxxx,
    We’re writing to remind you that starting June 20, 2024 the legacy Firebase Cloud Messaging (FCM) APIs will be discontinued. This change will cause the legacy APIs to return an increased number of error responses.
    The discontinued APIs will be completely shut down by July-August 2024.
    What you need to do
    If you’re still using legacy APIs to send messages with FCM, and do not expect the migration to the HTTP v1 API to be completed by June 20, 2024, please submit an extension request with Firebase Support before then to avoid disruptions in your service.
    We’re here to help
    We understand this change may take some planning, and we're here to support you during this transition. If you have any questions or need more information about the specific error codes and error messages, please review the Firebase FAQs.
    Thanks,
    - Todd on behalf of the Firebase team

     

    Firebase iOS SDK 업그레이드

     

    배치에서 사용하는 firebase-admin 버전

    요거 버전이 예전 버전이라서 그런가.. 음??

     

    분석

    Firebase에서 온 레거시 서비스 종료 메일

    그리고 저 메일이 시행된건 7월 22일에 기전 레거시 서비스가 중단된다고 하는데 우리가 발생한 문제는 8월 중순경 부터였다.

    의심은 가지만 시기상으로는...음.. 하지만 무엇인가 영향을 준것인가?? 합리적 의심이 든다. 하지만 확신이 안든다.. 일단 더 찾아보자.

     

    Firebase iOS SDK 업그레이드

    Swift로 개발한 iOS에 설정된 코코아팟의 라이브러리 버전은  FirebaseAnalytics (10.19.0) 이다.

    의심이 간다.. 그래서 푸시 토큰을 저장하고 있는 테이블에 단말기 정보를 확인해 보았더니 iOS, AOS 비등 비등하다.

    단말기에 상관없이 발생하고 있다. 이녀석은 아닌듯하다! 하지만 이번달 안에 코코아팟 라이브러리 업데이트 하고 버전업한 앱으로 출시하긴 해야겠다.

     

    배치에서 사용하는 firebase-admin 버전

    구글링 하다가 SDK을 V3에서 V4로 업데이트 하면 해결된다고 한다. 이게 우리 상황과 정확히 일치하는지는 모르겠으나 일단 해보기로 하였다.

     

    해결 시도

    해결 방향은 배치에서 사용하는 firebase-admin 버전이 유력해 보임으로 버전을 올려보자.

     

    0. 라이브러리 버전 업

    우리는 gradle을 사용하니깐 버전부터 올리자.

    6.8.0 -> 9.3.0

    dependencies {
      ...
      
      //  implementation 'com.google.firebase:firebase-admin:6.8.0'
      implementation 'com.google.firebase:firebase-admin:9.3.0'
      
      ...
    }

     

    1. 발송코드 개선

    버전을 올렸더니 기존에 동작하던 sendMulticast 함수 가 deprecated 되었다고 한다. sendAll 마찬가지..

    api를 찾아보니 sendEachForMulicast가 부하는 좀 있다는것 같은데 저희 서비스에는 무리가 없어보여 이걸로 선택하였다.

    예전에는 AOS, iOS에 따라서 파라미터 설정을 다르게 한것 같은데 데이터 형식은 동일하여서 TO-BE에서는 좀더 심플한 방법으로 일원화 하였다..

     

    • sendMulticast -> sendEachForMulicast
    • 전송 파라미터 일원화
    ...
    
        // TODO. AS-IS
        /*
        // AOS 설정
        Map<String, String> androidMap = ConversionUtils.objectToMap(data);
        AndroidConfig androidConfig = AndroidConfig.builder().putAllData(androidMap).build();
    
        // iOS 설정
        Map<String, Object> apnsMap = ConversionUtils.objectToMap(data);
        ApsAlert apsAlert = ApsAlert.builder().setTitle(data.title).setBody(data.contents).build();
        Aps aps = Aps.builder().setAlert(apsAlert).build();
        ApnsConfig apnsConfig = ApnsConfig.builder().setAps(aps).putAllCustomData(apnsMap).build();
    
        MulticastMessage.Builder messageBuilder = MulticastMessage.builder()
            .setAndroidConfig(androidConfig)
            .setApnsConfig(apnsConfig)
            .addAllTokens(targetTokens);
        */
    
        // TODO. TO-BE
        MulticastMessage.Builder messageBuilder = MulticastMessage.builder()
            .setNotification(Notification.builder()
                .setTitle(data.title)
                .setBody(data.contents)
                .build())
            .putData("title", data.title)
            .putData("contents", data.contents)
            .putData("notiKey", data.notiKey)
            .putData("externalUrlYn", data.externalUrlYn)
            .addAllTokens(targetTokens);
            
            
        BatchResponse response = messaging.sendEachForMulticast(messageBuilder.build());
        
    ....
    
    
        List<String> failedTokens = new ArrayList<>();
        if (response.getFailureCount() > 0) {
          List<SendResponse> responses = response.getResponses();
          for (int i = 0; i < responses.size(); i++) {
            if (!responses.get(i).isSuccessful()) {
              logger.info("############################## Failed to send message to token: " + targetTokens.get(i));
              logger.info("############################## Error: " + responses.get(i).getException().getMessage());
    
              failedTokens.add(targetTokens.get(i));
            }
          }
        }
        return failedTokens;

     

    2. 실패시 토큰에 is_deleted 플래그 갱신

    물리적으로 삭제하던 토큰 정보테이블에 is_deleted 플래그를 추가하고 갱신하는 방식으로 변경하였다. (당연이 연관된 쿼리들 모두 변경)

    왜냐하면.. fmc api 문제인 건들은 토큰을 삭제하면 안되는데.. 이미 사라져 버려서,, 몇달전 토큰정보로 마이그해야하는 상황이 발생했기에 물리적으로 지우지 말자!

     

    3. 테스트

    푸시도 잘오고, 조회쪽도 일단 잘된다.. 이단도 삼단도 잘 되겠지...?

     

    일단 내가할건 다 한거 같은데?? 테스트 후 문제없으면 릴리즈 ㄱㄱ싱하자.

    ㄱㄱ싱 했는데 문제가 또 발생했다 그전과 다르게 네트웍 관련 오류였다. 기존 오류는 해결된것 같은데.. FCM에 토큰을 100건씩 던지덜걸 이번에 개선하면서 속도도 개선하려고 400개로 올린게 문제인가. (API상에는 500개 까지 가능)

    List<Integer> resultList = Utils.getDivideList(dispatchLimit, 400);

     

    아래와 같이 타임아웃을 늘려보았다.

      FirebaseOptions options = new FirebaseOptions.Builder()
          .setCredentials(GoogleCredentials.fromStream(serviceAccount))
          .setConnectTimeout(10000)  // 10초 연결 타임아웃
          .setReadTimeout(10000)     // 10초 읽기 타임아웃
          .build();
      FirebaseApp.initializeApp(options, appTypeCd);

     

    확실히 속도도 빨라지고 문제가 해결되었다.

     

    문제가 발생하지 않으면 푸시쪽 포스팅은 없을것 같고 다음 분기때 배치를 큐베이스로 바꾸게 되면 그때 추가로 포스팅해야겠다.

     

    Firebase iOS SDK 업그레이드 하는건 iOS 앱 수정할때 같이할 예정이다. 간단한 작업이라서 포스팅할지는 고민이다.

     

     

    댓글

Designed by Tistory.