Google Cloud Functions のアンチパターンの回避(第 4 回): Node.js の Cloud Functions 関数内で Promise を適切に処理する方法
Google Cloud Japan Team
※この投稿は米国時間 2021 年 11 月 12 日に、Google Cloud blog に投稿されたものの抄訳です。
編集者注: 今後数週間にわたり、Google Cloud Functions の関数を記述するためのベスト プラクティスに注目するブログ投稿シリーズを公開していきます。これらのベスト プラクティスは、サポートチームがよく受ける質問や、よく見かける誤解を基にしています。こうした問題をここでは「アンチパターン」と呼び、これらを回避する方法をご紹介します。この記事は、そのシリーズの第 4 回です。
シナリオ
関数がデータベースに保存するデータが「未定義」のまま、あるいはキャッシュに保存された値のどちらかであることに気付きました。たとえば、1 時間ごとに 1 つのデータベースからデータを取得して、そのデータを変換し、変更されたデータを別のデータベースに保存する Cloud Functions の関数を呼び出す Cloud Tasks タスクがあるとします。しかし、データは未定義またはキャッシュに保存された値であることがわかりました。
よくある根本的な問題
未処理の Promise。
Cloud Functions の関数で「then-able」アプローチを使う際の一般的なアンチパターンに、未処理の Promise を見逃しやすいというものがあります。たとえば、次の例で問題を見つけることができるでしょうか。
これでは transformData(response.data) の呼び出しにどれくらいの時間がかかるか不明です。また、この呼び出しは非同期メソッドである可能性が高いでしょう。その結果、saveDataToDatabase メソッドは transformData() が完了する前に実行されるため、変数 dataNowTransformed は未定義のままデータベースに保存されます。
調べる方法
await を使用していない場合、async キーワードと await キーワードを使ってコードの可読性を向上することをおすすめします。
現時点で await に変換できないのであれば、ロギングレイヤを追加して(以下の例を参照)、未処理の Promise があるかどうかを確認する必要があります。
then-able 関数を使ってロギングレイヤを追加する方法
ロギングの方法は 2 つあります。
コールバックを変更して同期ロギングを行う
非同期ロギングによってコールバックの変更を避ける(then-able 関数を使用してロギングレイヤを追加する)
コールバックを変更してもかまわないと仮定します。同期ロギングレイヤは console.log() を使って追加できます。logData() 関数と呼ばれる同期的なメソッドを作成してコードをクリーンに保ち、コード内に多数の console.log() ステートメントが発生しないようにすることをおすすめします。
logData() では、次のようになります。
次に、コールバック内のコードを変更したくないと仮定します。以下のとおり、非同期ロギング メソッドを追加することをおすすめします。
1. 関数内に非同期 logDataAsync() メソッドを作成します。2. then-able() アプローチを使用して logDataAsync メソッドを呼び出します。
よりコンパクトに非同期ロギングのアプローチを適用する方法については、「その他の役立つヒント」セクションを参照してください。
then-able アプローチを使用して Promise を処理する方法
.then() コールバック内ではタスクを 1 つずつ実行することをおすすめします。ここで最初のアンチパターンの例に戻って、then-able アプローチを使うように更新します。エンドツーエンドの動作例は次のとおりです。
ただし、このような連続した .then() 呼び出し(Promise チェーンと呼ばれます)によって、コードが読みづらくなり保守も難しくなります。このコードを他の場所で見かけた場合、より簡潔に書く方法については、「その他の役立つヒント」セクションを参照してください。
可能であれば await を使用することをおすすめします。関数のイベント ハンドラ callToSlowRespondingAPI のコードが、より簡潔で理解しやすくなっている点に注目してください。さらに、こうした非同期メソッドの呼び出しになんらかの問題が発生した場合、return ステートメントで null や false を返す代わりに例外がスローされます。
その他の役立つヒント
Functions Framework を使ってローカルでテストしている場合、この Codelab を参照して、Visual Studio Code を使って Node.js 関数をローカルでデバッグする方法をご確認ください。
データをロギングする際は、データの大きさに注意し(ログのサイズの上限を参照)、データに機密情報や個人情報が含まれていないことを確認してください。
then-able() アプローチを使用すると、次のようなコードをよく目にするかもしれません。これは前述した then-able() の Promise チェーンの長いバージョンと機能的には同じですが、読みやすくするために async await アプローチを使用することをおすすめします。
- Cloud デベロッパー アドボケイト Sara Ford
- テクニカル ソリューション エンジニア Martin Skoviera