Cloud Functions for Firebase の関数をスケジューラから定期的に呼び出す

Firebase、、イイですね。。とくに Cloud Functions for Firebase とてもよいです。AWS Lambdaにくらべてシンプルですし。。

さて今回は、Firebaseに登録した関数を定期的に呼び出してみます。
[FirebaseとGoogle Cloud Platform をさわれる環境を構築する](https://qiita.com/masatomix/items/0ddbfacb9bc1797044a1) で作った環境をつかって、Cloud Functions for Firebaseに登録した関数を、[Cloud Scheduler ~~ベータ版~~](https://cloud.google.com/scheduler/?hl=ja) というGCPのスケジューラから定期的に呼び出してみます。


**--2019/09/21追記--**
今日時点、もうスケジューラはベータ版ではなく正式版のようで、以下の記事から「ベータ」の記述を削除しました。コマンドの``beta``をとったくらいで、基本は同じです。
**--2019/09/21追記 以上--**

Cloud Functions for Firebase を呼び出すには [Cloud Functions for Firebase でジョブをスケジューリング（cron）する ](https://developers-jp.googleblog.com/2017/04/how-to-schedule-cron-jobs-with-cloud.html) にある「App EngineのCron機能を使う」ってBest Practice?があるみたいなのですが、今回はCloud Scheduler ってのでやります。

具体的には「testTopic」というGCP上のTopicへのPublishに反応する関数を作成し、そこで実行したいロジックを呼び出します。そして、Cloud SchedulerからそのTopicへのPublishを定期的に行うことで、関数の定期実行を実現します。


## 環境

[FirebaseとGoogle Cloud Platform をさわれる環境を構築する](https://qiita.com/masatomix/items/0ddbfacb9bc1797044a1) で環境を作るとこんな感じになってるとおもいます。


```bash
$ tree -a
.
├── .firebaserc
├── .gitignore
├── README.md
├── firebase.json
└── functions
    ├── .eslintrc.json
    ├── .gitignore
    ├── package.json
    ├── src
    │   └── index.ts
    └── tsconfig.json
```

もしくはGithubにコードをあげてあるので、そちらからコード取得してください。環境構築は以下の通り:

```bash
$ git clone --branch pub_sub_trigger https://github.com/masatomix/fb_function_samples.git
$ cd fb_function_samples/functions/
$ npm install
$ cd ../
```

## やってみる


### 呼び出したい関数を作成してデプロイする

まずは実行したいロジックを作成します。

```typescript:src/logic.ts
export function want_to_execute() {
  console.log('実行したいロジック!')
}
```

つづいて index.tsにPub/Subトリガーの関数を定義して、そこで上記ロジックを呼び出します。


```typescript:src/index.ts
import * as functions from 'firebase-functions'

// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
//
// export const helloWorld = functions.https.onRequest((request, response) => {
//  response.send("Hello from Firebase!");
// });

import * as logic from './logic'

export const helloPubSub = functions.pubsub
  .topic('testTopic').onPublish(message => {
    logic.want_to_execute()
  })

```

いつものコマンドでFirebaseへ関数をデプロイします。

```bash
$ firebase deploy --only functions

✔  functions: functions folder uploaded successfully
i  functions: updating Node.js 8 function helloPubSub(us-central1)...
✔  functions[helloPubSub(us-central1)]: Successful update operation.

✔  Deploy complete!
Please note that it can take up to 30 seconds for your updated functions to propagate.
```


### スケジューラを設定する

つづいてスケジューラにスケジュールを登録します。もちろん画面からも登録できるのですが、今回はコマンドラインからやってみましょう。。
あ、そのまえに``gcloud``コマンドが、**Firebaseで使用しているのと同じプロジェクトに向いているか**を確認します。


```bash
$ gcloud config list
[core]
account = xx@ki-no.org
disable_usage_reporting = False
project = xxxxx-xxxxxxx  '←ココとか'

Your active configuration is: [default]
$
```

向いてない場合は、[Cloud SDK の初期化](https://cloud.google.com/sdk/docs/initializing?hl=ja) などを参考に設定を行ってください。

[gcloud scheduler jobs create pubsub](https://cloud.google.com/sdk/gcloud/reference/scheduler/jobs/create/pubsub) を参考にコマンドを打ってみます。


```bash
$ gcloud scheduler jobs list
ID         LOCATION     SCHEDULE (TZ)           TARGET_TYPE  STATE
test       us-central1  * * * * * (Asia/Tokyo)  HTTP         ENABLED  <- 前に追加していたヤツ 
topicTest  us-central1  * * * * * (Asia/Tokyo)  Pub/Sub      ENABLED  <- 前に追加していたヤツ 
$


$ gcloud scheduler jobs create pubsub testJob \
  --topic testTopic \
  --message-body='test' \
  --schedule '* * * * *' \
  --time-zone='Asia/Tokyo'

name: projects/xxxxx-xxxxxxx/locations/us-central1/jobs/testJob
pubsubTarget:
  data: dGVzdA==
  topicName: projects/xxxxx-xxxxxxx/topics/testTopic
retryConfig:
  maxBackoffDuration: 3600s
  maxDoublings: 16
  maxRetryDuration: 0s
  minBackoffDuration: 5s
schedule: '* * * * *'
state: ENABLED
timeZone: Asia/Tokyo
userUpdateTime: '2019-02-03T15:55:14Z'


$ gcloud scheduler jobs list
ID         LOCATION     SCHEDULE (TZ)           TARGET_TYPE  STATE
test       us-central1  * * * * * (Asia/Tokyo)  HTTP         ENABLED
topicTest  us-central1  * * * * * (Asia/Tokyo)  Pub/Sub      ENABLED
testJob    us-central1  * * * * * (Asia/Tokyo)  Pub/Sub      ENABLED ←追加された!
$
```

おおお、追加されたようですね。Scheduleは「* * * * *」で登録したので、1分おきにPublishが行われるはずです。

ちなみに message-body はカラだと怒られたので、適当に値を入れてます。
また、デプロイされた関数がListenしているTopic「testTopic」は、関数をデプロイしたときに自動で作成されるようです。



画面でも登録を確認してみましょう。
https://console.cloud.google.com/cloudscheduler にアクセスしてみると、、、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/c0f5ac17-d820-c7a0-d176-888870fa62fa.png)

確かに追加されてますね。よさそうです。

さて、最後にちゃんと定期的に実行されているか、関数のコンソールログを見てみましょう。
GCPの画面のメニューから、Cloud Functionsを選択 。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/4e02bbc4-4f22-13b4-3a48-8864e25e441c.png)


関数の一覧が表示されるので「helloPubSub」をクリック。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/fdd9fc46-4bfc-4b56-d4a0-066490287df3.png)

次の画面の右上に「ログの表示」とあるのでクリックすると、、、、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/b8f65a68-79fb-b595-5ca2-eee237282803.png)

たしかに1分ごとに関数が呼び出されているようですね！！


## まとめ

はじめFirebase Functionsのトリガーに「時間トリガー」がなかったので、定期実行できないじゃん、っておもったのですが、Cloud Schedulerという機能が追加されたので、コレをつかえば問題なさそうです。

おつかれさまでした。


## 関連リンク

- [Google Cloud SDK のインストール/アンインストールメモ(公式バージョン)](https://qiita.com/masatomix/items/57891a026856f5c39a7e) 公式のインストール手順。
- [FirebaseとGoogle Cloud Platform をさわれる環境を構築する](https://qiita.com/masatomix/items/0ddbfacb9bc1797044a1) ``brew cask``でのインストール手順(ベータの時に書いた記事なので、公式手順の方がイイかな)
- [Cloud Scheduler ~~ベータ版~~](https://cloud.google.com/scheduler/?hl=ja) ベータが取れたようですね
- [Cloud Scheduler クイックスタート](https://cloud.google.com/scheduler/docs/quickstart?hl=ja)
- [Firebase Cloud Functionsで定期実行してみる](https://qiita.com/jun1009/items/4145072dbb243c3edf9f) 外部サービス(cron-job.org)を使う手もあり