安心、安全なPubSub Functionの作り方
PubSub Function でピタゴラスイッチを作り安定稼働させることができたので、作る前から気をつけていたことや実際に動かしてみて気づいたことなどを羅列しておく。
全体
安易に例外で死んではいけない
これは一般的な Web アプリと一緒と言えば一緒。
- 手元の開発では例外で死ぬと PubSub に ack が返らず retry されるが、例外で死ぬのをくり返すだけ
- production (GCP) の場合は PubSub には nack は返らないので PubSub からは retry されない。これを retry するには Function そのものの設定で retry するしかないが、無条件 retry は上と同じ問題を抱えている
「例外」だけど例外的にではなく計算して死ぬ、くらいの気持ち。
cf. バックグラウンド関数の再試行 | Google Cloud Functions に関するドキュメント
機能をできるだけバラす
あくまで Function なので一つ一つの機能はできるだけシンプルに。なんらかのストレージや PubSub を利用しつつ次の Function を call する程度に留めるようにしておく。
バラしたFunctionを個別に実行、スキップできるようにしておく
何らかの仕組みを作っていると、
ここまでの処理は OK だけどここからが NG
みたいな状況は非常によくあるので、常に最初から全部を実行するしかない、という状況は避けておくと開発効率は比較的よくなる。
APIアクセス専用のclassだらけにする
上のバラし方はシーケンスでの分解だけど、もう一つのバラし方の基本はレイヤーで分けること。Function を書く際には OS で提供されている機能、言語内の標準機能だけを使うケースは稀で、ほとんどのケースで GCP の用意した API や外部の API を叩く処理が多く含まれる。ということは言い方を変えると API アクセス部分で死ぬ可能性だらけである。
この部分をそれぞれ専用の class に分割しておくとよい。
- これらの class で専用の retry の処理を仕込む
- 失敗の拾い方を個別に決めておく
- 例えば HTTP GET で 404 が「あり得る」なら「成功」として処理するなど
- mock や emulator が利用できるなら積極的に利用できるようにする
- できるだけ TDD を回す
API 頼みのコードを そのまま mock / emulator なしで書くと production 環境依存になりやすい。production 環境依存だと 1) 書いて、2) 実行して、3) テスト、デバッグする、までのサイクルが大きく重たくなってしまうので、開発速度が上がりにくく保守性も悪くなりやすいので、これを避ける。
外部APIだらけのコードをできるだけTDDっぽく作った話 - あーありがち(2020-03-01) なんかも参照してもらえれば。
必要なリソースをできるだけ早期に確認しておく
周知の通り Function にはメモリにも処理時間にも制限がある。そしてこれらの制限に引っかかった場合の timeout などの異常終了はアプリケーションレベルでは捕捉できず、GCP 内部の status では ok 以外の情報として取得できても log は debug level のものしかなく、PubSub 側でも異常を検知できない。
そこで Function の Execution time や Memory usage をちゃんと確認しておく必要がある。もちろんデータ量が増えた際に変わってくる部分はあるにせよ、ある程度設定可能なリソースの計画を立てておく必要があるし、場合によっては設計の変更も行う。
監視重要
Cloud Functions や AWS Lambda などのサーバレスサービスはとにかく「めちゃくちゃ簡単にプログラムが動かせる」かのようなイメージを抱いてもらおうと頑張っているが、サーバレスでは伝統的なサーバと違ってほとんとすべての情報が /var/log 以下から辿れるといったことはなく、後から何かを知ろうにも「何を使ったら何を知ることができるのか」を分かっていないといけない。
そこで Stackdriver のサービス群への習熟が極めて重要になる。
- Stackdriver Monitoring で ok 以外の status が発生していないか
- 同じく Memory usage や Execution times の数値が異常になっていないか
- 実行頻度、実行回数に異常がないか
- 多すぎる場合もそうだけど、例えば1日1回の定期実行が動いていません、も異常。
これらを適切に監視できるよう設定しておくと安心。