📘

AWS SQS で 外部システムとの連携を堅牢化した話

に公開

はじめに

こんにちは、Recustomer でエンジニアをやっている rikuto です!

どんなプロダクトを開発しているのか気になる方は下記のサービスサイトを見ていただければと思います。
https://recustomer.me/

弊社のプロダクトは、外部サービスとのAPI連携が非常に多いという特徴があります。 外部サービスとの連携はビジネスの要ですが、それに伴って開発チームを悩ませていたのが外部との通信の「不安定さ」でした。

今回は、外部連携において抱えていた問題に対して、Python製の非同期タスクキュー(Celery + Redis)の導入、そして AWS SQS(Simple Queue Service)へ移行することで解決した事例を紹介します。

直面していた課題:外部システムとのデータの受け渡しミス=致命傷

API連携において、以下の2つのパターンで問題が頻発していました。

  1. 外部サービスから受け取るべき情報を、うまく受け取れなかったケース(Inbound)
  2. 外部サービスに渡す情報を、渡せなかったケース(Outbound)

それぞれ深掘りしてみます。

1. 外部サービスからの情報を受け取れなかった場合

外部サービスとの連携がプロダクトの価値そのものである弊社にとって、これは致命的です。

こちらから能動的に再取得できる仕様ならまだ良いのですが、Webhookのように相手から送られてくるタイプの場合、「失敗したのでもう一度送ってください」 と相手にお願いしなければなりません。

しかし、お願いして即座に対応してもらえることは稀です。最悪の場合、データは失われたままで謝る以外に手立てがなく、ビジネス上の信頼損失に直結していました。

2. 外部サービスへ情報を渡せなかった場合

こちらは、エラー内容を修正して再送すれば良い話ですが、運用コストが膨大でした。
相手サーバーのダウンなどで、こちらが正常でも受け取ってもらえないこともあります。

  • 対象の特定が困難: どのデータが送信できていないのか確認が大変
  • リカバリの手間: 再送信するのが面倒

デプロイへの恐怖

これらの問題があるため、「関連する処理の変更を安易にデプロイできない」という心理的ハードルが生まれていました。

第1段階の解決策: Celery + Redis による非同期化

まず、「DB負荷によりリクエストを受け取れない」などという事態を防ぐため、Python界隈でよく見かける Celery + Redis を導入し、処理を非同期化しました。

これにより、リクエストの受け取り自体は安定しましたが、その他の課題はまだ残っていました。

前提として、Celery + Redis 構成そのものに問題があるという話ではありません。設定値などを調整することで改善される可能性はありますが、あくまで私が運用時に直面した課題として紹介します。

  • 失敗した内容の確認が面倒: Redisの中身を直接確認するのは手間がかかった。
  • 任意のタイミングでの再実行が難しい: 失敗したタスクだけを選んで手軽に再実行するやり方が分からなかった
  • スケールが難しい: キューの数に応じて Worker の台数をスケールするのが簡単ではなかった
  • 容量の問題: Redisの容量限界になると キュー に積めなくなってデータをロストしていた
  • 定期実行の重複: 本番環境などではAZ冗長性を考慮して複数台サーバーを建てますが、Celery Beat だとそれぞれが同一時刻に キュー を積もうとして処理が重複していた。

第2段階の解決策:AWS SQSへの移行

そこで導入したのが AWS SQS (Simple Queue Service) です。

1. 失敗時の可視化と調査

処理に失敗したメッセージを確認したい場合、AWSマネジメントコンソールから簡単に中身を確認できます。

詳細に入ると「どんなデータだったのか」がGUIですぐにわかるため、調査スピードが格段に上がりました。

2. Dead Letter Queue (DLQ) による再実行フロー

上記画像にもあるとおり、SQSには、処理に規定回数失敗したメッセージを別のキューに移動させる DLQ (Dead Letter Queue) という機能があります。

この仕組みにより、以下のフローが確立できました。

  1. 処理に失敗すると自動的にDLQへ移動する。
  2. 開発者はDLQのアラートを見て調査する。
  3. バグ修正などの対応を行う。
  4. 「再処理」ボタンを押して、通常キューにメッセージを戻す。
  5. 修正されたコードで再処理される。

外部への送信処理も同様です。送信したいデータをまずSQSに積み、Workerがそれを取り出して送信する。もし相手側のサーバーが落ちていても、DLQに行くので、後で再送すれば良いだけです。

「最悪、処理が失敗してもDLQに残るから大丈夫。修正、もしくは最悪リバートして再送すればいい」

この安心感が得られたことで、デプロイ障壁、堅牢性が改善されました。

重要な注意点:冪等性(Idempotency)の担保

SQSなどで再実行可能な構成を導入する上で、一つだけ強く意識しなければならないことがあります。それは 「冪等性(べきとうせい)」 です。
つまり、最初の処理がエラーになったとしても、再送時の処理がその影響を受けないようにする必要があります。

以上、AWS SQSを活用した外部システム連携の堅牢化についてご紹介しました。


最後まで読んでいただきありがとうございました!
弊社の他のメンバーもアドベントカレンダーで記事を毎日投稿しているので、興味ある方は是非!!
https://qiita.com/advent-calendar/2025/recustomer

Discussion