前置き
Firebase Functionsで、日次のバッチ処理をする場合に、処理を並列に実行して、すべての処理が完了する時間がを短くしたい場合がありました。具体的には、Firestoreのコレクション内の複数のドキュメントの一つ一つに、時間がかかる処理をしたい場合です。
なお、ここでの並列とは、Functions自体を複数に分けて、それぞれ別のインスタンス上で処理を実行させることを意味しています。Promiseを使った非同期処理による並列ではありません。
Functionsを並列に実行する方法
Stack OverFlowに参考になる質問があります。
How to invoke other Cloud Firebase Functions from a Cloud Function
-
Cloud Pub/Sub トリガーを使って、特定のトピックのFunctionsを複数実行させる
- Pub/Subを利用するには有料プランにする必要がある
-
Firestore トリガーを使って、Firestoreに複数ドキュメント作成して、onCreateイベントを複数実行させる
- Firestoreトリガーが重複発火する問題がある(詳しくは「Cloud FunctionsのCloud Firestoreトリガーの重複発火を防ぐ、より良いアプローチ
」を参照)
- Firestoreトリガーが重複発火する問題がある(詳しくは「Cloud FunctionsのCloud Firestoreトリガーの重複発火を防ぐ、より良いアプローチ
※ どちらのケースでもFunctionsの呼び出し回数は増えるので課金に影響があります。
今回は、問題の少ない、Pub/Subを使ったアプローチを試してみました。
Cloud Pub/Sub トリガーを使って、Functionsを並列実行する
FunctionsからPub/Subにメッセージを発行するには@google-cloud/pubsubを利用します
npm install @google-cloud/pubsub
Functionsのサンプルコードは以下の通りです。
import * as functions from "firebase-functions";
import { PubSub } from "@google-cloud/pubsub";
// スケジュール実行される
export const scheduleFunctions = functions
.region("asia-northeast1")
.pubsub.schedule("*/5 * * * *") // 検証のため5分毎にしている
.timeZone("Asia/Tokyo")
.onRun(async context => {
const pubsub = new PubSub();
for (var message of ["hello", "world"]) {
const data = JSON.stringify({ message: message });
const dataBuffer = Buffer.from(data);
// Pub/Sub 特定のトピックにメッセージ送信
const eventId = await pubsub.topic("topic-functions").publish(dataBuffer);
console.log(eventId);
}
});
// Pub/Sub 特定のトピックにメッセージ受信で実行される
export const topicFunctions = functions
.region("asia-northeast1")
.pubsub.topic("topic-functions")
.onPublish(async (message, context) => {
await new Promise(resolve => setTimeout(resolve, 5000)); // 検証のため5秒待つ
console.log(Buffer.from(message.data, "base64").toString());
console.log(context);
return true;
});
実行結果
制限
Functionsのスケーラビリティには制限があります。未検証ですが、最大同時呼び出し数 1,000
に該当すると思います。
※上記のコードを使って、同時実行数100までは検証しました。
まとめ
Pub/Subを使って、1つのFunctinosから複数のFunctionsを発行できました。業務への組み込みはこれからなので、まだ見えていない課題はあるかもしれません。
別の並列化の方法や間違っている部分があったらご指摘ください。