CurateBot Devlog 10: 트윗을 보내는 예약된 Firebase 기능

우리에게 필요한 유일한 백엔드는 스캔할 트윗을 확인하면서 매시간 실행되는 클라우드 기능입니다. 커밋은 here 이며 주요 변경 사항은 functions/src/index.ts file

Firebase 기능



Firebase 함수는 서버리스 함수입니다. Firebase CLI에 자바스크립트 함수를 제공하면 이를 업로드하고 유지 관리하거나 설정할 필요가 전혀 없는 환경에서 실행할 수 있습니다.

이러한 기능은 HTTP 트리거, 데이터베이스 변경에 대한 트리거 또는 Pubsub를 통한 트리거에서 실행됩니다. Firebase는 또한 Pubsub를 통해 다른 서비스와의 통합을 제공합니다. 그 중 하나는 Cloud Scheduler service입니다. Pubsub에 게시할 수 있는 관리형cron 서비스로 생각할 수 있습니다.
pubsub.schedule() 트리거를 사용하도록 firebase를 지정하면 기본적으로 pubsub 함수 트리거일 뿐이지만 CLI는 Cloud Scheduler 서비스에서 일정을 설정합니다.


export const tweetScan = functions.runWith(runtimeOpts).pubsub.schedule('every 1 hours').onRun(async (context) => {
  const currentHour = new Date().getUTCHours();
  const currentDay = new Date().getUTCDay();
  const currentIdx = currentDay*24+currentHour;

  logger.info("Starting scan", {currentHour, currentDay, currentIdx});

  await firestore.collection('users').where('isActive', '==', true)
  .where('scheduleEnabled', 'array-contains', currentIdx.toString()).get()
  .then((query: admin.firestore.QuerySnapshot) => {

    const promises: Array<Promise<any>> = [];
    query.forEach((doc: admin.firestore.DocumentSnapshot ) => {
      promises.push(processUser(doc));
    })

    return Promise.all(promises);
  })
  .then(() => {
    return firestore.collection('system').doc('stats').update({
      lastRun: admin.firestore.FieldValue.serverTimestamp(),
    })
  })
  .then(() => {
    logger.info("Done scan");
  })
  .catch((err: Error) => {
    logger.error(err);
  })
});


이 스크립트가 수행하는 모든 작업은 프런트엔드에서 설정할 수 있는 일정과 일치하는 시간 인덱스를 계산한 다음 일정에 해당 시간 슬롯이 있는 활성 사용자가 있는지 확인하는 것입니다. 각각에 대해 processUser() 함수를 실행합니다.

일부 시스템 통계는 프로세스에서 업데이트됩니다.

사용자 처리



해당 시간 슬롯이 있는 각 사용자에 대해 가장 최근에 대기열에 있는 트윗을 가져와서 저장된 API 키를 사용하여 트위터에 게시합니다! 그런 다음 계정에서 트윗을 삭제합니다.

async function processUser(doc: admin.firestore.DocumentSnapshot): Promise<any> {
  const uid = doc.id;
  const userKey = doc.get('accessToken');
  const userSecret = doc.get('secret');

  return doc.ref.collection('tweets').where('queued', '==', true).orderBy('added').limit(1).get()
  .then((query: admin.firestore.QuerySnapshot) => {
    if (query.size) {
      const tweetDoc = query.docs[0];
      const tweetText = tweetDoc.get('tweet');

      logger.info("Got tweet for user", {uid, tweetText});

      if (tweetText) {
        const client = new Twitter({
          consumer_key: apiKey,
          consumer_secret: apiSecret,
          access_token_key: userKey,
          access_token_secret: userSecret,
        });

        return client.post('statuses/update', {status: tweetText})
        .then(tweet => {
          logger.info("Tweet sent!", {tweet});
          return firestore.collection('system').doc('stats').update({
            tweetsSent: admin.firestore.FieldValue.increment(1),
          })
        })
        .then(() => {
          return tweetDoc.ref.delete();
        })

      }
      return tweetDoc.ref.delete();
    }

    logger.info("No more scheduled tweets for user", {uid});
    return doc.ref.update({
      isActive: false,
    });
  })
}


트윗은 여러 키가 필요한 NPM 모듈을 사용하여 전송되며 첫 번째 키 쌍(소비자 키/비밀)은 이전에 등록할 때 얻은 봇의 API 키입니다. 이는 CLI 명령을 사용하여 Firebase 함수의 구성 공간에서 설정됩니다.

firebase functions:config:set twitter.api_key="***" twitter.api_secret="***"


두 번째 키 쌍(액세스 토큰 키/비밀)은 사용자가 로그인할 때 제공한 키로, 이를 통해 계정에 게시할 수 있습니다.

배포 중



Firebase는 이 기능을 예약하므로 이를 달성하기 위해 백엔드에 대해 걱정할 필요가 없습니다. 실제로 일정 기능을 처음 배포할 때 Firebase CLI는 필요한 API를 활성화하는 과정을 거치며 일정 비용이 월 $0.10이므로 결제를 업그레이드하라는 메시지도 표시합니다.



Cloud Scheduler용 Google Cloud 관리 콘솔을 살펴보면 새로운 항목이 추가된 것을 볼 수 있습니다(필요한 경우 여기에서 이 기능을 수동으로 트리거할 수도 있으므로 테스트에 유용함).




이 단계에서 CurateBot은 기능이 완성되었습니다! 이 서비스는 이제 대량으로 트윗을 로드하고, 사용자가 트윗을 큐레이팅하고, 일정을 선택하고, 트윗이 해당 일정에 게시되도록 할 수 있습니다! Twitter의 AI Bot 계정에 필요한 모든 것, UI 점검에 대한 게시물이 하나 더 있지만 그 외에는 완벽하게 작동합니다.

좋은 웹페이지 즐겨찾기