AWS SQS × ECS 実践の整理

なぜ id=1 は失敗し、id=3 は成功したのか

Slack Metricsのローカル環境とstg環境がどうつながり、どこで取り違えが起きたのかを、実際のAPI・SQS・CloudWatchログに沿って整理します。結論は、Wi‑Fiよりも「入口のURL」「DBごとのID」「キューを読むWorker」の3点です。

TL;DR

  1. workspace_id はチャンネル番号ではなく、DB内のSlackワークスペース管理番号。
  2. ローカルDBでは1、stg RDSでは3。同じ対象でもDBが違えば番号は一致しない。
  3. stgのid=3同期は成功。直後のid=1エラーは、キューに残っていた別メッセージ。

01workspace_idの正体

Slackのチャンネル番号ではなく、アプリがワークスペースを管理するためのDB主キーです。

workspace_idとchannel source_idの違いを示す階層図
workspace_idは親となるワークスペースのDB番号。SlackチャンネルIDとは別物です。
項目意味
workspaces.idアプリDB内のワークスペース管理番号ローカル=1 / stg=3
channels.workspace_idどのワークスペースに属するか3
channels.source_idSlack側のチャンネルIDCから始まるID

X-WORKSPACE-ID: 123 は「3番チャンネルを同期」ではなく、「stg RDSの workspaces.id=3 に紐づくSlack全体を同期」という指定です。

02同じSlackなのに、なぜ1と3?

内部IDは環境ごとのDBで別々に採番されます。名前が同じでも番号は共有されません。

ローカルDBのid1とstg RDSのid3を比較する図
IDはSlackそのものの番号ではなく、各DBが付けた番号です。
APIの入口参照DB使うID
localhost:8080ローカルPostgreSQL1
api.stg.example.comstg RDS3

環境とIDはセット。 localhostから送ったid=1をstg Workerが処理すると、stg RDSにid=1がないため not found になります。

03stgで成功する正しい一本線

入口から保存先まで、すべてstg側へ揃えると迷いません。

stg APIからSQSとECS Workerを経てRDSへ保存する処理フロー
APIは受付係、SQSは仕事箱、Workerは実作業係です。
curl --request POST \
  'https://api.stg.example.com/api/workspace-sync?from=2026-08-12&to=2026-08-13' \
  --header 'X-WORKSPACE-ID: 123'
APIログPOST /api/workspace-sync
status=202
WorkerログReceived message
body=workspace-sync
完了ログSuccessfully handled message

Wi‑Fiが原因とは確認されていません。 最初のcurlで確認できた直接原因は、HTTPの80番へ接続した一方、ALBにはHTTPS 443しかなかったことです。

04ローカルWorkerを同時に動かすと?

同じAWSキューを見ていれば、ECS Workerとの競合Consumerになります。

受信したWorker参照先起こり得る結果
ECS Workerstg RDSstgのIDなら正常処理
ローカルWorkerローカルPostgreSQLstgのIDがなくnot foundになる可能性

stg動作確認中はローカルの MODE=sqs go run main.go を停止し、ECS WorkerだけをConsumerにするのが最も分かりやすい運用です。

ここは推測と事実を分ける。 ローカルWorkerが起動していれば競合し得ます。ただしCloudWatchの /ecs/slack-metrics-worker-stg に出たfailはECS Workerのログです。ローカル標準出力が自動転送されたわけではありません。

05実際のログを時系列で読む

成功と失敗は同じ処理ではなく、メッセージIDが異なる別々の仕事でした。

今回の接続失敗とSQS成功失敗を区別するタイムライン
1つの処理が成功後に失敗したのではなく、別メッセージが続けて処理されました。
出来事確認結果判定
http://ALBへcurlポート80にリスナーなしAPI到達前に失敗
message 14690a72-… / id=3Successfully handled messagestg同期成功
message 7669f475-… / id=1WorkspaceRepo.Load: not found古い別メッセージが失敗
CloudWatchでは時刻だけでなく message_id を見る。同じIDの Received messageSuccessfully handled message を1組として追う。

結論

  1. ローカル試験はlocalhost・ローカルDB・id=1、stg試験はHTTPSのstg API・RDS・id=3に揃える。
  2. stg試験中はローカルWorkerを止め、AWS SQSを読むConsumerをECS Workerだけにする。
  3. 今回のid=3は成功済み。id=1のfailはキューに残っていた別メッセージとして切り分ける。