Server Actionが断続的に実行されない問題

profile image

Vercelのサーバーレス環境でServer Actionコールバックが断続的に実行されない問題の原因分析と解決方法。

この記事は Jetbrains's Coding Agent Junie junie logoによって翻訳されました。誤訳があれば教えてください!

問題

サーバーサイドで以下のようなMixpanelトラッキングコードを実行した際、イベントが断続的にのみ記録される現象が発生しました。

typescript
mixpanel.track(event, { distinct_id: userId, properties }, err => {
  if (err) {
    reject(err);
  } else {
    resolve("success");
  }
});

ローカル環境ではすべてのイベントが正常に記録されましたが、Vercelデプロイ環境では一部のイベントのみが記録される問題がありました。

原因

原因を見る前に、Vercel Functionについて理解しましょう。Vercelでは、Vercelにデプロイされた環境に対してVercel Functionという機能を提供しています。

Vercel Functionについて簡単に説明すると、Vercelにデプロイされたすべてのサーバーサイドでのコード実行はVercelのインフラ環境下で実行されるということです。つまり、FaaSが適用されるということです。

Faasとは?

FaaSはFunction as a Serviceの略で、サーバーレスコンピューティングを実装する方法の一つです。ここでのFunctionは私たちが開発時に使用するあのFunctionであり、これらの関数をクラウドサービスにアップロードして必要な時だけ呼び出す概念です。
つまり、FaaSを使用するとサーバーを開発する必要なく関数だけを作成して実行できるようになります。
Vercelのこのような機能のおかげで、私たちはサーバー設定を特に行わなくてもAPI RoutesやSSRなどを利用できるのです。

Note

VercelのServerlessアーキテクチャはAWSのLambdaを通じて動作します。

問題が発生したコードも**サーバーアクション(Server Action)**として設定されサーバーで実行され、Vercelがサーバーレスをベースに動作するため、コードがサーバーレス関数として登録されました。

しかし、サーバーレス関数は実行中にプロセスが終了する可能性があり、この場合非同期タスクが完了する前に関数が終了する可能性がありました。つまり、callback関数が実行されずイベントが正常に送信されなかったのです。

解決方法

したがって、コードを以下のようにPromiseでラップし、すべてのイベントが正常に記録されるようになりました。

typescript
return new Promise((resolve, reject) => {
    mixpanel.track(event, { distinct_id: userId, properties }, (err) => {
      if (err) {
        reject(err)
      } else {
        resolve('success')
      }
    })
  })

トラッキングコードをサーバーサイドで実行する理由

では、なぜmixpanel.trackのようなトラッキングコードをクライアントサイドで実行しなかったのでしょうか?

  • データの整合性:クライアントからイベントを直接送信する場合、ユーザーのブラウザ設定(例:広告ブロッカー)やネットワーク問題によりイベントが欠落する可能性があります。サーバーサイドで実行すると、これらの外部要因を減らし、より信頼性の高いデータ収集が可能になります。
  • ビジネスロジックとの統合:トラッキングイベントがサーバーサイドロジック(例:決済処理、ユーザー認証など)と密接に関連している場合、サーバーで直接処理する方が自然で効率的です。例えば、決済完了後にイベントを記録するには、サーバーで決済成功を確認した後にトラッキングするのが適切です。
  • パフォーマンス最適化:クライアントでトラッキングリクエストを処理すると、追加のネットワーク呼び出しが発生し、ページ読み込み時間が長くなる可能性があります。サーバーサイドで処理すると、クライアントの負担を減らしユーザー体験を向上させることができます。

これらの理由から、可能であればクライアントではなくサーバーサイドで実行する方がより正確で安定した指標を得ることができます。


参照

❤️ 0
🔥 0
😎 0
⭐️ 0
🆒 0