Twilio+SQS+Lambda 構成で発生した「再送ループによる課金」事例と防止策

Twilio+SQS+Lambda 構成で発生した「再送ループによる課金」事例と防止策

Twilio API + Amazon SQS + AWS Lambda の構成で発生した、意図しない SMS 課金インシデントの事例を紹介します。Lambda の終了処理失敗による SQS のリトライ設計不備が原因でした。同様の構成を検討するエンジニア向けに、原因と再発防止策を解説します。

対象読者

  • Twilio API を利用した開発を検討しているエンジニア
  • AWS Lambda や Amazon SQS を組み合わせた非同期処理設計を行うエンジニア
  • Slack などのチャットツールと外部サービス連携を行いたい開発者
  • 再送制御や冪等性設計について具体的な事例を知りたい方
  • クラウドサービスの利用時に課金リスクへの備えをしたい方

はじめに

本記事では、Twilio API を利用した SMS コマンド機能の検証中に発生した、意図しない課金の発生事例 について報告します。

当該インシデントは、筆者が以下の記事シリーズを執筆する過程において発生しました。

[Twilio+Slack] Slack に SMS 送信コマンドを実装する: SQS+Lambda での非同期処理構成

Twilio API では容易に SMS を送信できる一方で、キューや非同期処理を組み合わせた設計においては、意図しないリトライや再送によって課金が過剰に発生するリスク があります。

本記事では、実際に検証環境で発生した課金トラブルについて、その原因と再発防止策を共有します。ポイントは、「非同期処理における副作用(API 呼び出し)が終了処理の失敗によって重複実行される場合がある」 という設計上の落とし穴と、それを防ぐための 冪等性設計とリトライ制御の重要性 です。

1. インシデント概要

発生時期

2025 年 4 月、Twilio API を利用した検証中に発生。

検証環境構成

  • Slack からのコマンド入力
  • AWS Lambda → Amazon SQS 経由で非同期的に SMS 送信
  • SQS から Lambda ワーカーがメッセージを受信
  • Lambda 内で Twilio API により SMS を送信
  • Lambda の終了処理が正常に完了しなかった場合、SQS がエラーと判断してメッセージを再投入 → 再送発生

1

事象

  • Lambda 内で Twilio API 呼び出しは成功していた
  • しかし、Lambda の終了時にエラーが発生
    • 例: API 呼び出し後の終了時に context.succeed() 相当の処理を行わず例外がスローされた。これにより、Twilio API の呼び出し自体は成功しているにもかかわらず、Lambda はジョブ失敗とみなされ、SQS 側で再送が行われる状態となっていた。
  • そのため SQS がジョブ失敗と判断し、同一メッセージを再送
  • 冪等性を考慮していなかったため、再送ごとに新規の SMS 送信が実行され、本来数件程度の送信が想定されていたところ、1 件のコマンドに対し数十件の SMS が送信され、数千円規模の課金 に至った

2. 詳細な発生状況

実装していたフロー

  1. Slack から指定のコマンドを送信
  2. API Gateway → Lambda によってコマンドを受理
  3. Lambda から SQS にメッセージ送信
  4. 別の Lambda(ワーカー)が SQS からメッセージを受信
  5. Lambda 内で Twilio API により SMS 送信を実行
  6. 送信成功後、Lambda の終了処理でエラー発生 → SQS から再送 → 再度 Lambda 起動
  7. 冪等性チェックがなかったため、再起動のたびに新しい SMS が送信された

3. 課金が発生した構造と要因

要素 内容
Lambda 終了処理の失敗 API 呼び出しは成功していたが、Lambda 側での終了処理が失敗し、SQS が再送を実行した
冪等性の欠如 再送時に同一リクエストであることを判別できず、都度 SMS が送信された
使用していた番号の地域差 Twilio の US 番号から日本番号への送信だったため、1 回あたりの単価が高額
番号取得コストのトレードオフ 日本番号の取得は高額であり、検証時には US 番号を利用していた
課金監視手段の不十分さ Usage Trigger などによる事前の課金制御を行っておらず、発生後に気づいた

4. 再発防止策

Lambda ワーカー設計の見直し

  • Lambda の終了処理を適切に実装し、API 呼び出し成功時は必ず SUCCESS で終了するよう修正
  • エラー発生時にも「どの処理までが完了したか」を記録する
  • 処理途中でのタイムアウト回避のため、Lambda のタイムアウト時間を適切に設定

冪等設計の導入

  • メッセージごとに一意のリクエスト ID を付与
  • 再送時にリクエスト ID をチェックし、すでに送信済みであれば SMS 送信処理をスキップ

SQS 設定の見直し

  • Visibility Timeout を Lambda の処理時間 + α に調整
  • Maximum Receives と Dead Letter Queue(DLQ)の設定により無限再送を防止

Twilio 課金対策

  • Usage Trigger による総量監視の導入(ただし根本的な再送制御が重要)
  • 開発環境では送信先をホワイトリスト制限し、誤送信を防止
  • 番号選定(US 番号 vs. 日本番号)の費用対効果を検討
  • 検証時には Twilio API 呼び出し部分をコメントアウトする、またはモック化することで、送信動作の確認と課金発生を切り分けてテストする

5. まとめ

Twilio API の運用においては、非同期メッセージング × 冪等性欠如 × ワーカーエラー時の再送設計不備 という条件が重なると、検証環境であっても想定以上のコストが発生します。

特に、Lambda の中で副作用(API 呼び出し)が発生しているにもかかわらず、終了時のエラーでリトライされる という構造は、見落とされやすい設計上の罠です。

同様の構成を採用する際は、
「再送時にも同一リクエストかどうかを必ず判別し、冪等性を担保する」
この設計思想を持つことが、不要なコスト発生を防ぐ上で不可欠です。

本事例が、Twilio および AWS を組み合わせたシステム設計を行うエンジニアにとって、課金リスクを低減するための注意喚起となれば幸いです。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.