☁️

CloudFront Functionsのテストツール「cfft」を導入した

2024/12/18に公開

はじめに

こんにちは、READYFORでエンジニアをしているshmokmtです。
READYFORでは歴史的な背景[1]からLPを様々な構成でホスティングしています。

  • Netlify
  • CloudFront + S3
  • CloudFront + ALB + Ruby on Rails
  • STUDIO

しかし、近年では非エンジニアが主体となってLPを制作する際のファーストチョイスとして、STUDIO[2]を利用する機会も増えてきました。その結果、REDYFORでは下記の構成でホスティングしているLPをSTUDIOに移行する機会が増えてきました。このLPを移行する作業では、元のURLのリンクは切らしたくないため、リダイレクトは必須の要件でした。

  • CloudFront + S3
  • CloudFront + ALB + Ruby on Rails

リダイレクトの要件

リダイレクトの要件は以下のとおりです。

  • 特定のprefixを持つパスをリダイレクト対象とする。(例: /corp/info
    • ただし、リダイレクト対象のprefixの中でも特定の文字列を含むパスだけは業務の関係上、リダイレクトしてはならない。(例: /corp/a/corp/b はリダイレクトするが、/corp/c はリダイレクトしてはならない。)
  • リダイレクトする際にあらかじめコードに保持したマップを元にパスのマッピング処理をする必要があるときもある。(例: /corp/dog/wanko にリダイレクトする。dogとwankoはあらかじめリダイレクト用のソースコード内でマップで関連付けされている。)

上記の要件とREADYFORの現状のインフラ構成を踏まえた上でCloudFrontのレイヤーで統一的にリダイレクトすることにしました。

CloudFront Functionsでのリダイレクト

CloudFrontのレイヤーでリダイレクトをする場合は以下のサービスが選択肢として候補に挙がります。

・CloudFront Functions
・Lambda@Edge

今回のユースケースではURLを元にした条件分岐が複雑ではあるものの、aws-sdkを必要とする処理は一切ありませんし、ライブラリも必要としません。
そこで今回はランタイムが安定しているCloudFront Functionsでリダイレクトのコードを運用することとしました。

CloudFront Functionsを運用することで見えてきた課題

CloudFront Functionsの運用が始まると次第に条件分岐は複雑化していき、下記のようなコードになりました。

↓あくまでもイメージです。

function handler(event) {
  try {
    const request = event.request;
    const uri = request.uri;
    if (uri.startsWith("/A")) {
      return processA(request);
    } else if (uri.startsWith("/B")) {
      return processB(request);
    } else if (uri.startsWith("/C")) {
      return processC(C);
    } else if (uri.startsWith("/D")) {
      return processD(request);
    } else if (uri.startsWith("/E")) {
      return processE(request);
    } else if (
      uri.startsWith("/OTHERS") 
    ) {
      return processOthers(request);
    } 
}

そのため、コード内の条件分岐を修正したときに手元ですぐに動作確認をしたいというモチベーションが生まれてきました。手元ですぐに動作確認ができれば、PRのレビュープロセスも楽になると考えました。
動作確認をするための選択肢として、awscliのaws cloudfront test-functionが挙げられます。しかし、複数のテストケースを実行したい場合にawscliで実行するのは煩わしさがありました。
そこでほかに良いツールがないか探していたところ、fujiwaraさん作のcfftを発見しました。
検証してみたところ、ユースケースとマッチしていたため採用しました。

https://github.com/fujiwara/cfft

下記のようにcfft test で全てのテストケースに対してテストが実行されるため、awscliで感じていた課題感が解決されました。

↓テストの実行例

❯ cfft test
2024-09-18T13:19:46+09:00 [info] function apply-redirect found
2024-09-18T13:19:47+09:00 [info] function is not changed
2024-09-18T13:19:47+09:00 [info] [testcase:redirect to A] [etag:ETVPDKIKX0DER] testing function
2024-09-18T13:19:47+09:00 [info] [testcase:redirect to A] ComputeUtilization: 7 optimal
2024-09-18T13:19:47+09:00 [info] [testcase:redirect to A] TestFunction API succeeded
2024-09-18T13:19:47+09:00 [info] [testcase:redirect to A] checking function output with expected value
2024-09-18T13:19:47+09:00 [info] [testcase:redirect to A] expect and actual are equal
2024-09-18T13:19:47+09:00 [info] [testcase:redirect to B] [etag:ETVPDKIKX0DER] testing function
2024-09-18T13:19:48+09:00 [info] [testcase:redirect to B] ComputeUtilization: 7 optimal
2024-09-18T13:19:48+09:00 [info] [testcase:redirect to B] TestFunction API succeeded
2024-09-18T13:19:48+09:00 [info] [testcase:redirect to B] checking function output with expected value
2024-09-18T13:19:48+09:00 [info] [testcase:redirect to B] expect and actual are equal
2024-09-18T13:19:48+09:00 [info] 2 testcases passed

おわりに

READYFORで抱えていたCloudFront Functionsの課題は fujiwara/cfft により解決されました。
複雑な条件分岐を含んだCloudFront Functionsを運用している方は是非検討してみてください。

参考

脚注
  1. 雑に言ってしまえば、すぐに返済できない技術的な負債のこと。返済しても事業インパクトがあまり大きくないため、長年優先度が低いままになってしまっている。 ↩︎

  2. https://studio.inc/ ↩︎

READYFORテックブログ

Discussion