개발

[Firebase] Functions로 간단한 Push Notification 자동화

Onve 2024. 11. 26. 15:45

 

Firebase는 개인 프로젝트 뿐만 아니라 모든 프로젝트에 굉장히 큰 도움이 되는 서비스이다.

 

백엔드 개발자 없이도 쉽게 백엔드가 있는 서비스를 만들 수 있게 해주며, 그 외에도 Authentication이나 Cloud Messaging 등 꼭 필요하지만 개발하기 귀찮은 요소들을 많이 가지고 있다.

 

그 중 Functions(이전 Cloud Functions)와 Realtime Database를 이용해서 간단하지만 강력한 Push 알림을 개발 할 수 있어서, 개발해보았다.

 


Functions 사용하기

Functions의 배포 방식은 다음과 같다.

 

  1. 노트북 등에서 Firebase Initializing 후 Functions를 연결한다.
  2. Functions 코드를 작성하고, 그 후 Firebase에 업로드한다.
  3. 잘 작동하는지 로그를 확인한다. 

생각보다 간단해 보이지만, 여러 과정이 섞여있다. 하나하나 가보자.

 

1. Firebase Initializing

우선, Firebase 콘솔에서 빌드 > Functions로 들어간다.

단, Fuctions는 최소 Blaze 금액제로 업그레이드를 해야만 사용이 가능하다. (월 200만회까지는 무료)

 

업그레이드를 하면, Firebase 에서 알려주는 대로 하면 된다.

 

$ npm install -g firebase-tools

 

우선 npm이 설치되어있다면, 다음과 같이 작성하여 firebase-tools를 설치한다.

 

이때, -g로 인해 오류가 발생한다면, 앞에 sudo를 붙여 관리자 권한으로 설치시켜주면 된다.

 

그 후, firebase 프로젝트를 생성한다.

 

$ firebase init

 

이러면 Firebase 프로젝트를 내 컴퓨터에 생성할 수 있다.

 

Firebase 프로젝트 생성 시 과정들이 있는데, 필요한 요소에 Functions를 넣고(Space) 엔터를 눌러줘야 Functions 파일이 생성된다.

 

 

2. Functions 작성하기

나의 경우 아예 서버 없이 Push Notification을 보내야 했다.

 

Realtime Database의 정보를 이용해서 Push Notification을 보내는 형태의 코드를 예시로 사용할 예정이니, 다른 방식으로 사용 시 참고용으로 사용하면 될 것 같다.

 

제대로 Firebase 프로젝트를 생성했다면, functions 폴더가 생기고 그 안에 index.js가 생성되어야 한다.

 

package.json을 보면 알 수 있다싶이, firebase function은 메인 파일을 index.js로 가져가기 때문이다.

 

그럼 이제, function을 작성할 타이밍이다.

 

우선, 코드 내용 중 가장 중요한 요소는 functions 모듈을 적용하는 것이다.

const functions = require("firebase-functions");

// Push Notification을 위한 admin이 필요한 경우
const admin = require("firebase-admin");
admin.initializeApp(); // 관리자 권한 실행

 

이렇게 하면 기본 요소는 모두 마무리되었다. 

 

이제, Function을 작성하면 되는데, Firebase Functions가 인시하기 위해서는 다른 방식으로 작성을 해야한다.

 

나의 경우, 정해진 시간마다 함수를 작동시키기 위해서 Pub/Sub 방식의 함수를 사용하였다.

exports.YOURFUNCTIONNAMEHERE = functions.pubsub
    .schedule("every 1 minutes")
    .onRun(async (context) => {
    	// 원하는 코드 작성
    }
)

 

이런 형태로 작성하면 된다.

 

나의 경우는 매 1분마다 맞는 일정이 있는지 확인하고, 만약 일정이 존재하면 요청한 모두에게 Push 알림을 주는 아이돌 관련 어플리케이션을 만들고 있어서, 다음과 같이 코드를 추가적으로 작성하였다.

 

exports.sendNotification = functions.pubsub
    .schedule("every 1 minutes")
    .onRun(async (conext) => {
        // 현재부터 1분 체크
        const now = moment().tz("Asia/Seoul").startOf('second').toISOString();
        const bufferTime = 60000;

        const eventsRef = admin.database().ref("events");
        const subscribersRef = admin.database().ref("subscribers");
        
        // events 중 현재부터 1분 내에 일정이 있는지 확인
        const snapShot = await eventsRef
            .orderByChild("date")
            .startAt(now)
            .endAt(moment(now).add(bufferTime, 'milliseconds').startOf('second').toISOString()) 
            .once("value");
        
        // 만약 일정이 있는 경우 sendNotificationToAllUsers 함수(따로 생성)로 전달
        if (snapShot.exists()) {
            const notificationPromises = [];
            
            snapShot.forEach((childSnapShot) => {
                const event = childSnapShot.val();

                if (!event.notificationSent) {
                    notificationPromises.push(
                        sendNotificationsToAllUsers(subscribersRef, event)
                    );
                }
            });
            await Promise.all(notificationPromises);
        }
        return null;
    }
)

 

여기서 sendNoticationsToAllUsers 함수의 경우 같은 index.js 파일에 firebase functions 함수가 아닌 일반 JS 함수로 작성하였다.

 

이렇게 함수 작성이 완료되었다면, 이제 남은건 배포 뿐이다.

 

3. 배포하기

배포하는 건 어렵지 않다.

 

우선, functions 디렉토리로 이동해야 한다.

$ cd functions

 

그 뒤에는, functions만 설치를 요청하면 된다.

/functions $ firebase deploy --only functions

 

이러면 여러가지 작업을 한 뒤에, functions에 올라간다. 이때부터는 firebase console의 대시보드를 통해 작동 여부를 확인할 수 있다.

 

이와 같이, 매 시간마다 60회의 트리거로 작동하는 것을 확인할 수 있다.

 


Functions 지불 금액

나의 경우, 일분에 1회씩 작동하는 함수이기 때문에 월 단위에서는 다음과 같이 사용하게 된다.

 

한시간 60분 X 하루 24시간 X 한달 31일(최대) = 43200회

 

Functions의 경우 월에 호출 무료 횟수는 총 200만회로, 나의 4만 3천 200회에 비해서는 매우 넉넉한 편이다.

 

다만, 시간 단위가 아니라 사용자를 pub-sub 하는 방식으로 구현한다면 Functions의 지불 구조를 잘 확인할 필요가 있다.