🌊

Firebase Functions の callable が遅いので別の方法で解決してみた

2024/09/29に公開

Firebase Functions の callable って課金しないと超遅いですよね。
起動に3~5秒くらいかかるからずっと悩んでました。

ただ、我慢の限界だったので違う方法で解決する方向にしました。

Callable が遅い原因

callable が遅い原因としては
その API が使われてないとすぐにスリープ状態になるからです。

無料枠なんだからずっと起動する訳ないでしょw
必要な時だけ動くから、最初の起動だけは遅いよ。
早くしたかったら課金してねw

みたいな感じで Google さんに言われてると思って大丈夫です。(← 流石にない)

Trigger 関数で解決する

callable が遅いのは無課金でやっているからな訳なので
課金したら解決なんですが、極力お金はかけたくないはずです。
(課金対象はインスタンスやメモリ周りの事です)

そこで登場するのが Trigger 関数です。

これは何故かずっとインスタンスが立ちっぱなしの状態で
create, update, delete 処理をした時に爆速で動きます。

って言うことでコイツを使います

実装例

まずは API 処理で送っていた引数と何の処理をしたいかが分かるように
ドキュメントを作成します。
(下記はあくまで最小限の一例なので適当に追加してもらってOKです)

json
{
  id: uuid,
  type: 'setCurrentUser',
  status: 'pending',
  arguments: {
    userId: 'userId'
  }
}

上記のデータがドキュメントに作成されたら
Trigger 処理が発火されるはずです。

ts
export const method = onDocumentCreated(
  'trigger_methods/{triggerMethodId}',
  async (event) => {
    const data = event.data.data();

    if(data.type === 'setUser'){
      // ここで callable で行っていた処理をする
    }
  }
)

type というデータを持って処理を分岐させているので
同じコレクション内でも別々の処理を発火させることができるので type は必須と思ってます。

あとは callable で設定した API の中身をここで行えば良いので
データの追加や更新、削除などが完了するのを見守るくらいです。

あと問題なのは、どうやってフロント側で更新されたデータを受け取るかです。

Snapshot と Completer で非同期処理を自作する

普段から使っている Future 処理では
何も考えずに非同期処理を行っていると思います。

ただ、今回の場合、非同期処理を自作する必要が出てきます。
なぜ、自作する必要があるかというと

フロント側から Firestore へ書き込む処理は非同期処理で行われますが
Trigger 処理で行われる処理はバックエンド側の処理なのでフロント側が関与できないからですね。
(ちょっとわかりづらくてすみません、やる気出した時にちゃんと書きます)

と言う事でドキュメントを Snapshot で監視する必要が出てきます。
json で設定した id がドキュメントIDを意味するので、そのドキュメントを監視します。

あとはドキュメントを監視しつつ
Completer 使って非同期処理にしたら完成。

dart
final completer = Completer();

db.collection('trigger_methods').doc(id).snapshot().listen((event) {
  final data = event.data();

  if (data?.status != Keys.pending) {
    completer.complete();
  }
});

await completer.future;

意外と簡単。
だけど、既に作成した API が沢山あってコレを1つ1つやり直すのか...と考えると涙が出てきます。

もっと前に気が付いてたら、どれだけ楽だったか・・・

Discussion