A deep dive into hooks | Workflow SDK
27分 45秒
Vercel Workflow SDK活用術:HooksとWebhooksでマジックリンク認証を簡単実装
この記事は動画の内容を元にAIが生成したものです。正確な情報は元の動画をご確認ください。
ポイント
- •Vercel Workflow SDKのHooksとWebhooksが、マジックリンク認証のような複雑な非同期処理の実装を劇的に簡素化する手法を紹介します。
- •従来のロジック分散やデータベースによる状態管理の課題を解決し、約50行の簡潔なコードで耐久性の高い認証システムを構築可能です。
- •開発者は本記事から、Vercel Workflowを活用して待機中にコンピューティングリソースを消費しない「ゼロコンピュート」を実現する方法を学べます。
皆様、本日はありがとうございます。VercelのワークフローチームのPranayです。そして、同じくワークフローチームのNateです。
Nateと私はワークフローチームの立ち上げ当初から関わっており、この半年でリリースした機能の中でも、HooksとWebhooksは特に気に入っている機能の一つです。本日は、まさにこのHooksとWebhooksについてお話しします。
HooksとWebhooksは、私たちにとっても非常に強力な機能であり、その理由をいくつかのデモを交えてご説明いたします。
マジックリンク認証とは?従来の課題
まず、おそらく皆様にも馴染み深い「マジックリンク認証」から始めましょう。マジックリンク認証とは、ログインフォームにメールアドレスを入力し、受信したメール内のリンクをクリックするだけでサービスにログインできる仕組みです。
実際、VercelがZeitと呼ばれていた頃、マジックリンクは唯一の認証方法でした。当時はこのシステム全体を自社で構築していました。
この経験から、私たちにはある種のPTSDがあります。Workflowを使わずにこのようなシステムを実装することは、見た目以上に複雑だからです。ロジックは複数のファイルに散らばり、状態を追跡するためにデータベースを導入する必要があります。あっという間に複雑化してしまいます。
従来の多段階プロセス
従来のWorkflowなしでマジックリンク認証を実装する場合、以下のような課題とプロセスが存在します。
-
ログインフォームの送信時
- セッションを生成し、Redisのようなデータベースに保存する必要があります。データが永遠に残らないように、TTL(Time To Live)を設定し、期限切れにする必要があります。
- 次に、ログインメールを送信します。このメール送信が失敗する可能性があり、その場合、ログイン機能が動作せず、ユーザーは不満を感じます。
- もしセッション情報が残ってしまった場合、後からcronジョブや手動でデータベースをクリーンアップする手間が発生します。
-
ユーザーがメールのリンクをクリックした時
- データベースを照会し、最初のステップで構築された状態を復元する必要があります。
このように、たとえ非常にシンプルなコンセプトであるにもかかわらず、コードはすぐに「スパゲッティコード」と呼ばれるような複雑なものになってしまいます。これは、多くの開発者が経験する共通の課題と言えるでしょう。
Vercel Workflow SDKによるマジックリンク認証の実装
では、Workflowを使ってこの機能をどのように実装するのか見てみましょう。Workflow SDKを使用したマジックリンクの実装は、以下のようになります。
// 実際のコードブロックは文字起こしにないため、概念のみ記述
// function MyMagicLinkWorkflow() {
// useWorkflow();
// const webhook = await createWebhook({ respondWithManual: true });
// await sendLoginEmail(webhook.url);
// await Promise.race([webhook, sleep(5 * 60 * 1000)]); // 5分間のタイムアウト
// // ... 認証成功後の処理 ...
// }
私たちはuseWorkflowディレクティブを使用します。これは、この関数がWorkflow関数であることを意味します。最初に行うことは、workflowパッケージから提供されるcreateWebhook関数を呼び出すことです。
この例ではrespondWithManualオプションも使用しています。これは、HTTPリクエストに応答を送信する責任が、このWorkflow関数にあることを意味します。これにより、ログイン後にリダイレクトなどの処理を自由に行うことができます。
自動リトライと耐久性
最初のエンドポイントと同様に、ログインメールを送信するsendLoginEmailステップがあります。これは「Uステップ関数」であり、もしメール送信のような処理が失敗した場合でも、Workflow SDKは自動的にリトライを行います。従来の方式では手動でエラー処理を実装する必要がありましたが、Workflowの耐久性(Durability)という側面がすでにメリットを提供しています。
Promise.raceとWebhookオブジェクトの活用
ここで非常に興味深いパターンをご紹介します。私たちはPromise.raceとsleep関数を5分間に設定して使用しています。これは、webhookオブジェクトがPromiseを実装しているため、可能になっています。
このWebhookへのリクエストを待機するには、単にawait webhookと記述するか、この例のようにPromise.raceを使用します。従来の機能であれば、タイムアウトのためのオプション引数があることを期待するかもしれませんが、Promise.raceを使うことで、よりクリーンに、そして柔軟にタイムアウトをモデル化できます。
このプリミティブなアプローチの美しさは、Workflow SDKが提供するすべてのものがPromiseとして公開されている点にあります。そのため、await Promise.raceのような標準的なJavaScriptパターンがそのまま機能します。
データベース不要な状態管理
もう一つ重要な点として、この実装にはRedisのようなデータベースが不要であることです。従来の例では、タイムアウトを実装するためにRedisのTTLを利用していましたが、Workflowではsleepプリミティブを使用します。これにより、複雑なデータベース管理や、後から散らかったデータベースをクリーンアップする必要もなくなります。これは最高の部分です。
その後、WorkflowはWebhookリクエストに応答し、ログイン成功ページにリダイレクトし、ユーザー情報を取得してクライアントに返します。これらすべてのロジックが、たった約50行のコードでマジックリンクの実装として完結します。これは本当に素晴らしいことです。
実際の動作デモとオブザーバビリティ
それでは、マジックリンクのデモを実際に見てみましょう。
-
メールアドレスの入力とWorkflowの開始
- メールアドレスを入力すると、Workflowが開始され、メールが送信されます。Webhookはただ待機している状態です。
-
Workflowの一時停止とゼロコンピュート
- 注目すべきは、Workflowが現在「一時停止」しているという点です。つまり、ユーザーがメール内のリンクをクリックするのを待っている間、コンピューティングリソースは一切消費されていません。これは非常に効率的です。
-
Vercelダッシュボードでの監視(オブザーバビリティ)
- Vercelのダッシュボードでは、Workflowの実行状況を詳細に確認できます。開始からの時間、Workflowの入力(フォームに入力したメールアドレスなど)が見て取れます。
- 特に興味深いのは、「hook is just waiting(フックが待機中)」と表示されている点です。そして、私たちが指摘したように、この間は実際に何のコンピューティングも実行されていません。Webhookの待機も、
sleepの待機も、どちらも実際のコンピューティングを伴わないのです。 - フックとスリープは
Promise.raceで競合しているため、Workflowを続行するにはどちらか一方が先に完了する必要があります。
-
リンククリックとWorkflowの完了
- ユーザーがメール内のリンクをクリックすると、ログイン成功ページにリダイレクトされます。これはWorkflowロジック内のステップの一つです。
- Vercelダッシュボードに戻ると、Workflowが正常に完了し、タイマーが停止していることが確認できます。
まとめ
Vercel Workflow SDKのHooksとWebhooksは、マジックリンクのような複雑な非同期フローの実装を劇的に簡素化します。従来の課題であった、ロジックの分散、データベースによる状態管理、エラー処理、クリーンアップといった問題を解決し、開発者がより本質的なロジックに集中できるようになります。
- 簡潔なコード: わずか50行程度のコードでマジックリンク認証を実装可能。
- 耐久性: 自動リトライ機能により、メール送信などの失敗に強いシステムを構築。
- 効率性: ユーザー操作の待機中にコンピューティングリソースを消費しない「ゼロコンピュート」を実現。
- 柔軟性: WebhookオブジェクトをPromiseとして扱うことで、
Promise.raceなどの標準的なJavaScriptパターンを駆使し、タイムアウトや並列処理を柔軟に制御。 - データベース不要: Redisのような外部データベースを使用せず、Workflow自体が状態管理やタイムアウト処理を担う。
Workflow SDKが提供するプリミティブは、非同期処理の新たな可能性を開き、開発体験を大きく向上させる強力なツールとなるでしょう。
参考動画: https://www.youtube.com/watch?v=zsxelWLj_m0