Firebase Cloud Functionsで定期実行してみる

FirebaseのCloud Functionで定期実行をしようと試行錯誤したときのメモです📝
#はじめに: やろうと思ったきっかけ
- リマインダーっぽく`Cloud Messaging`を特定の日時に発動したいなーと思った💡
- 公式の`Cloud Messaging`スケジューリング機能は特にない💧
- `Node Schedule`とかを使おうと思ってもFunction内のタスクが保持されないので無理😓

#定期実行の選択肢
公式のFireCastの動画では以下の2つを案内していた。

**1. AppEngineからCloud Pub/Subトリガーで実行する方法**
**2. 外部のCronサービスからHttpトリガーで実行する方法**

私はAppEngineを触ったことなく、コマンド打ってて何やってるかよく分からなくなってきたので、確実に理解できそうな **[ 2. 外部のCron ]** を選択。

App EngineアプリのサンプルはGitHubに公開されているので、GCPに明るい方は **[ 1. AppEngine ]** でやったほうがかえって早いかもしれません。 **[ 1. AppEngine ]** について知りたい方は、他の方のQiita記事や公式の記事をみてください💁

- [Google Cloud FunctionsをGoogle App Engine + Cloud Pub/Sub + Nodeで定期的に実行する - Qiita](https://qiita.com/miya0001/items/ad0412ca379505088339)
- [Google Developers Japan: Cloud Functions for Firebase でジョブをスケジューリング（cron）する](https://developers-jp.googleblog.com/2017/04/how-to-schedule-cron-jobs-with-cloud.html)

><2019.4.22追記>
Cloud Functions中の設定・実装のみで完結できるようになったみたいです
書いている方がいらっしゃったのでリンク貼らせていただきま〜す
[Firebase Cloud Functionsの定期実行が、それ単体で簡単にできるようになった！](https://qiita.com/RyotaMurohoshi/items/607258c35c935c581d26)


```swift:お断り.swift
guard let user = "外部のcronサービスでもいいやの人" else { return }
```

#外部のCronサービス
無難に公式で案内されている`cron-job.org`を使ってみます。
[cron-job.org - Free cronjobs - from minutely to once a year.](https://cron-job.org/en/)

とりあえず、トップからサインアップしてアカウントを作成しておきましょう。

#Cloud Functions側の準備
ここはユースケースによって異なるかと思いますのでざくっと。

```javascript:index.js
//必要モジュールのセットと初期化
const functions = require(`firebase-functions`);
const admin = require(`firebase-admin`);
admin.initializeApp();
const db = admin.database();

//Httpトリガの関数（今回はこれを紹介したかっただけ）
exports.hogehoge = functions.https.onRequest((req, res) => {

  const targetTime = `2018-07-13 10:10`;
 
  db.ref().child(`hogehoge`).orderByChild(`date_time`).equalTo(targetTime).once(`value`).then（snap => {

   //やりたいことを書く（データベースの書き込みなど）[略]

  }).catch(reason => {

   //エラー処理[略]

  });
 
});
```

おい、そこ省略しないで〜って方は、公式ドキュメントや以下らへんのサンプルを確認してくださいませ。
[firebase/functions-samples: Collection of sample apps showcasing popular use cases using Cloud Functions for Firebase](https://github.com/firebase/functions-samples)

作った関数を以下でデプロイ。

```
$ firebase deploy --only functions
```

すると、こんな感じで

```
Function URL (addMessage): https://us-central1MY_PROJECT.cloudfunctions.net/addMessage
```

エンドポイントURLが出力されるので、メモしておきましょう 📝

#定期実行する前にとりあえずテスト
上記のURLをブラウザに入れて実行。意図した通りに動いているかを確認してください。
（URLメモし忘れたって人は、もう一回デプロイしてもいいですが、管理画面の`開発` > `Functions`の、デプロイした関数のところに書いてあるのでそれをコピペしてもいいです）
#cronを実行する
1. `cron-job.org`に先程つくったアカウントでログインして「Cronjobs」を選択
2. 右上の「+ Create cronjob」をクリック
3. Titleに適当な名前をつけて、テストで使ったリクエスト先のURLを記載🌏
4. お好みのScheduleを設定
5. Create cronjobを押すと開始（自動的にEnableされます）

以上で終了です！

#Cloud Messagingを定期実行する場合は？

ここは色々やり方があると思うのですが、冒頭で記載したように、リマインダーみたく指定日時に`Cloud Messaging`を実行する場合、

例えば...

1. 予め`Realtime DataBase`トリガーや`Cloud FireStore`トリガーを利用して、`Cloud Messaging`でプッシュ通知を送る関数を作っておく（[例] プッシュ通知管理のツリーにデータが追加されたらプッシュ通知を実行する）
2. クライアントからDBにリマインダー送信情報を書き込む処理を作る
3. Httpトリガーで関数を呼んで、その時間に送るリマインダーがないかをチェックして、あった場合は1で使用しているプッシュ通知管理のところにデータを書き込めば勝手に送信される（ & リマインダーの情報を削除しておくかステータスを書き換えておくといいかも）

処理を順番に追うと、、、

（ユーザー）リマインダーツリーに書き込む→
（cron-job.org）Httpリクエスト→
（Cloud Functions Cron用関数）Httpトリガで関数が呼ばれる→
（Cloud Functions　Cron用関数）該当時間のリマインダーが引っかかる→
（Cloud Functions　Cron用関数）その情報を使ってリモートプッシュのツリーに書き込む→
（Cloud Functions　プッシュ通知用関数）DBトリガのプッシュ通知用関数で通知が送られる

という感じですね。

こういう風にすれば、ユーザー操作によってリマインダーを送る日時が変わったとしても、リマインダーツリーの情報をUpdate/Deleteすれば良いだけなので楽ちんです☺

#参考
[Cloud Functions について学ぶ（動画シリーズ）  |  Firebase](https://firebase.google.com/docs/functions/video-series?hl=ja)