Google cloud schedulerを試した



# はじめに
Google cloudでcronサービスがあるといいなーと思っていたら[Google cloud scheduler](https://cloud.google.com/scheduler/)のbetaが公開されたので早速試してみました。この記事のポイントは次の二点です。

- POSTするときはgcloudコマンドを使ってheaderのContent-Typeを明示して下さい
- ケースによってはGoogle apps scriptで十分な気もする 

# 前準備

Schedulerのテスト用にFirebase FunctionsでAPIサーバーを立てて、Google Apps Scriptで動作確認しました。この辺りの詳しい方法はここでは書きませんので、ググって下さい。

## APIサーバーの用意

[Firebase Functions](https://firebase.google.com/docs/functions/)で次のようなプログラムをdeployしました。単純にパスワードを確認して、合っていればFirestoreの`echoTest`にドキュメントを追加するだけです。

```javascript
const functions = require('firebase-functions');

const admin = require("firebase-admin");
const serviceAccount = require("./.private/firabaseKey.json");
admin.initializeApp({
    credential: admin.credential.cert(serviceAccount)
});

exports.echoTest = functions.https.onRequest((request, response) => {
    const db = admin.firestore();

    if (!db) {
        response.status(500).end();
    }

    if (request.body.password !== 'iceageiscomingthisisreallyhappening') {
        response.status(401).end();
        return;
    }

    if (typeof request.body.message === 'undefined') {
        response.status(400).end();
        return;
    }

    const createSec = Math.round((new Date()).getTime() / 1000);
    const data = {
        message: request.body.message,  
        createSec: createSec 
    }

    db.collection('echoTest').add(data).then(ref =>{
        response.send(request.body.message);
    }).catch(err=>{
        response.status(500).end();
    });
});   
```

## APIサーバーの確認

多くの方イケてるツールを使うのでしょうが、私はいつも[Google Apps Script](https://developers.google.com/apps-script/)を使って確認しています。GAPのプログラムはこんな感じになります。

```javascript
function echoTest() {
  const params = {
    'password': 'iceageiscomingthisisreallyhappening',
    'message': '200 OK!'
  }
  const options = {
    'method' : 'post',
    'payload' : params
  };
  const res = UrlFetchApp.fetch('https://YOUR-CLOUD-FUNCTION/echoTest', options);
  Logger.log(res);
}
```

これでFirestoreにデータが追加される事を確認しました。

# Scheduler GUI設定

Google cloud consoleに Cloud Schedulerというメニューが出来ているので、それをクリックしてcronを新規作成します。まず始めは次のような設定を試しました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/29999/d82ede0c-6297-b2ec-6a57-96bdbdee1477.png)

設定したCRONは"Run Now"をクリックすれば実行出来ます。
![CS4.PNG](https://qiita-image-store.s3.amazonaws.com/0/29999/d22b3058-e697-1a59-94e4-c5f9b1e1b339.png)

ただし、これは残念ながらエラーになってしまいました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29999/0d35e124-8c1d-abda-b196-e97ae62a0abd.png)

Scheduler側のエラーを見ても良く分からなないので、Firebase Functionsのログを見るとauthentificationでエラーになっていました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/29999/ce4e1473-f666-03f5-ab43-87623cbbd097.png)

どうやらFunctionsの次の行で401エラーになっているみたいです。

```javascript
    if (request.body.password !== 'iceageiscomingthisisreallyhappening') {
        response.status(401).end();
        return;
    }
```
多分bodyが正しく送られていないのだなーと思い、試しにrequest.bodyでのチェックを全てやめて、GETでurlを取得したら正しく動きました。やはりpostのbodyが正しく設定されていないようです。ここでbodyをjson形式にしたり色々試したのですが、結局GUIでは動きませんでした。誰かやり方分かった方は教えてくれると嬉しいです。

# CUIでのScheduler設定

仕方がないのでCUIで`gcloud`コマンドを使いました。私はgcloudのインストールが面倒なのでGCPの[Cloud Shell](https://cloud.google.com/shell/docs/)を使っています。コマンドは次の通りです。

```bash
gcloud beta scheduler jobs create http gcp-sche-api \
--schedule="*/3 * * * *" --uri="https://your-cloud-function/echoTest" \
--headers Content-Type=application/x-www-form-urlencoded \
--message-body="message=hoge&password=iceageiscomingthisisreallyhappening"
```

ポイントは3行目でbodyのcontent-typeを明示的に指定しています。ヘッダの設定は[MDNのマニュアル](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)を参考にしました。

これでFunctionがFailしなくなりました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/29999/146b1fc8-7209-080d-5215-edac4d86d629.png)

# GAPのTriggerとの違い

Google Apps Scriptの下りで気づいた方もいらっしゃると思いますが、GAPでもTriggerを使えばcronのような事が出来ます。従ってちょっとしたcronはこっちの方が簡単だと思います。私は個人開発で作ったサービスで１５分に一回動くTriggerを設定して運用していますが、もう半年以上問題は起きていません。ただ、一回や二回失敗しても問題ない処理内容なので、たまに動作してなくても分からないですが。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/29999/7cea6df0-e60d-5c76-65dd-5a2233cdf5ed.png)

ただしジョブの失敗が致命的なシステムの場合はそうはいきません。Schedulerの方はジョブが失敗した時のretryを`--max-attempts`オプションなどで[細かく設定できます](https://cloud.google.com/sdk/gcloud/reference/alpha/scheduler/jobs/create-http-job)ので、そういう場合はSchedulerを使う事になると思います。