はじめに
CloudFunctionsで何らかの処理を実行して、その何分後かに別の処理を呼び出したいことがあります。
だけどsetTimeoutを使いたくない。事前にジョブを登録しておくわけにもいかない。
そんな時に以下の方法で実装してみました。
-
cloudSchedulerに対して、実行させたい日時(例:○分後)にジョブを登録。
-
実行時刻になると処理が呼び出される。
-
処理が終わったら不要になったジョブを削除。
サンプルコード
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const { google } = require('googleapis');
const cloudScheduler = google.cloudscheduler('v1beta1');
const moment = require('moment');
process.env.GOOGLE_APPLICATION_CREDENTIALS = 'path/to/serviceAccountKey.json';
async function authorize() {
const auth = new google.auth.GoogleAuth({
scopes: ['https://www.googleapis.com/auth/cloud-platform'],
});
return await auth.getClient();
}
const projectId = 'my-project-id';
const locationId = 'us-central1';
const topicName = 'my-topic-name';
const jobName = 'my-job-name';
// 10分後処理実行を登録する処理
exports.setTriggerIn10minutes = functions.https.onRequest(
async (req, res) => {
// 現在時刻の10分後を取得し、cronフォーマットを生成
const cronStr = moment().add(10, 'minutes').format('m h D M *');
// GCPのOAuth認証
const authClient = await authorize();
// ジョブ追加リクエストを作成
const request = {
parent: `projects/${projectId}/locations/${locationId}`,
resource: {
name: `projects/${projectId}/locations/${locationId}/jobs/${jobName}`,
schedule: cronStr,
pubsubTarget: {
topicName: `projects/${projectId}/topics/${topicName}`,
data: Buffer.from(`${topicName} ${cronStr}`).toString('base64'),
},
},
auth: authClient,
};
// APIリクエスト
try {
const response = (await cloudScheduler.projects.locations.jobs.create(request)).data;
console.log(JSON.stringify(response, null, 2));
} catch (err) {
console.error(err);
}
res.status(200).send('OK');
}
);
// 10分後に呼び出される処理
exports.beCalledAfter10minutes = functions.pubsub.topic(topicName).onPublish(
async (event, context) => {
const pubsubMessage = event.data;
console.log(Buffer.from(pubsubMessage, 'base64').toString());
// TODO: 実際にやることを記述
// GCPのOAuth認証
const authClient = await authorize();
// ジョブ削除リクエストを作成
const request = {
name: `projects/${projectId}/locations/${locationId}/jobs/${jobName}`,
auth: authClient,
};
// APIリクエスト
try {
await cloudScheduler.projects.locations.jobs.delete(request);
} catch (err) {
console.error(err);
}
}
);
実行確認
最初の処理
ブラウザから以下のURLにアクセスし、Cloud Functionsを実行します。
https://location-id-my-project-id.cloudfunctions.net/setTriggerIn10minutes
Cloud Functionsのログを確認し、setTriggerIn10minutesが正常に実行されたことを確認します。
Cloud Schedulerのジョブ一覧を確認し、トピック:my-topic-nameのジョブが10分後の実行予定で追加されたことを確認します。
10分後に呼び出される処理
Cloud Functionsのログを確認し、beCalledAfter10minutesが正常に実行されたことを確認します。
Cloud Schedulerのジョブ一覧を確認し、トピック:my-topic-nameのジョブが削除されたことを確認します。
注意事項
-
FirebaseのSparkプラン(無料)では使えませんでした。Blazeプラン(従量制)にする必要あり。
-
Cloud Schedulerの管理者権限をIAMで割り当てる必要あり。
-
実行時刻は秒単位での指定はできません。
といった制約があるので使える場面は少ないかもしれませんが、もしもの時に役立てばと思います。