App Store Connect APIのレート制限に当たったら、無限リトライを止め、アップロード、状態確認、バックグラウンド処理の3系統を分離してください。今週は、HTTP応答とTransporterの配信ログを保存し、指数バックオフ付きの有限リトライへ変更したうえで、TestFlight用の実ビルドを1回だけ通して復旧結果を確認するのが安全です。
この内容は、リモートMacでTestFlightビルドを自動送信する独立開発者、複数アプリのRunnerを運用する小規模チーム、fastlaneや独自スクリプトの保守担当者向けです。単に「ビルドが表示されない」だけで、すぐAPI制限と判断したくない人にも役立ちます。
01障害の正体を分けるログ診断
最初に見るべきなのは、失敗した処理の名前ではなく、どのサービスへの通信が止まったかです。Appleのレート制限識別資料では、API応答を使って制限の発生を判断する考え方が示されています。HTTPステータス、応答本文、ヘッダーをまとめて保存してください。
一方、TransporterやXcodeの配信ログは、バイナリの転送と配信受付を確認する材料です。Build Uploads APIはアップロード資源の状態を扱いますが、転送完了はTestFlightで利用可能になったことを意味しません。
Appleのレート制限識別ドキュメントとBuild Upload Statusesの公式説明を照合すると、次のように切り分けられます。
| 観測された現象 | 証拠を取る場所 | 次の判断 |
|---|---|---|
| API呼び出しが拒否される | HTTP応答、応答本文、ヘッダー | リトライを止め、制限情報を記録する |
| バイナリ転送が失敗する | TransporterまたはXcodeの配信ログ | APIの再試行ではなくアップロード経路を確認する |
| 配信後もビルドが処理中 | Build Uploadsの状態、App Store Connect画面 | 再アップロードせず、処理状態を別管理する |
| 状態が古いまま変わらない | 最終確認時刻、Build ID、Webhookイベント | 重複ポーリングを止め、イベントまたは補償確認へ移る |
App Store Connect APIのエラー処理では、ステータスだけでなくエラーの詳細を読む必要があります。公式のエラー処理ガイドにない独自の閾値や固定待ち時間を、Appleの仕様として扱ってはいけません。
02App Store Connect APIのレート制限を招く重複ポーリング
よくある原因は、1回の公開作業を複数のJobが監視している状態です。たとえば、アップロード直後のスクリプト、失敗後に再起動したRunner、管理画面の監視処理が同じBuild IDをそれぞれ取得すると、1回の配信が大量の状態確認へ膨らみます。
固定間隔を機械的に設定するより、タスク単位で次の情報を保存してください。
- App ID、Build ID、発行用キーの識別子を脱敏して記録する
- 実行中のJobに一意のタスクIDを付ける
- 1タスクあたりのリクエスト予算と同時実行数を設定する
- 最終確認時刻と最後に確認した状態を永続化する
- 成功、失敗、処理中、手動確認待ちの停止条件を分ける
「App Store Connect APIはどのくらいの頻度でポーリングすべきか」という問いに、全環境共通の秒数で答えることはできません。公式資料に固定の待機間隔を見つけられない場合は、応答内容、処理段階、直近の失敗回数に応じて間隔を伸ばしてください。制限時の具体的な応答情報は、必ずAppleの限流識別資料で確認します。
429応答を受けたときの処理
App Store Connect APIが429を返した場合、同じリクエストを即時に繰り返すのは避けます。レスポンスに再試行に関する情報が含まれていればそれを優先し、なければ指数バックオフと上限付きの補償処理に切り替えます。
ここで重要なのは、再試行回数や待機時間をAppleの確定仕様として決めないことです。導入時にはログへ応答全体を保存し、文書更新や実環境の変化があれば見直してください。
03アップロードと処理確認の分離
安全な公開フローは、次の4層に分けます。
- IPAやアーカイブを生成する。
- TransporterまたはXcodeでバイナリを送信する。
- 配信受付をログで確認する。
- Build ProcessingとTestFlightでの利用可否を別に確認する。
Appleのアップロード手順でも、ビルドのアップロードと、その後App Store Connectで処理される段階は別の操作として扱われています。Build Uploads APIの資料も、アップロード資源をAPIから扱うための情報です。
そのため、APIの状態取得に失敗したからといって、すぐ同じIPAを再送信しないでください。配信ログに受付済みの記録があり、Build IDも一致しているなら、必要なのは再アップロードではなく状態確認の復旧です。逆に、転送自体が失敗しているなら、APIのポーリングを増やしても解決しません。
Webhookを使う状態確認
Webhookは、App Store Connect側のイベントを受け取れる場合に、常時の状態取得を減らす選択肢です。Webhook通知の設定資料とWebhookEventTypeの定義を確認し、受信イベントをBuild IDとタスクIDに結び付けてください。
Webhookだけで最終確認を完結できるとは限りません。イベント受信後にApp Store Connect画面やAPIで確認する補償処理を残し、イベントが遅延・重複した場合も同じタスクを二重完了させない設計にします。
04有限リトライと冪等復旧
リトライ対象を一つのキューにまとめると、アップロードの失敗が状態確認まで巻き込みます。少なくとも「アップロード実行」「受付確認」「処理状態」「TestFlight利用可否」を別の状態として保存してください。
例として、ログ上の値は次のように脱敏します。
task_id=TASK-<REDACTED>
app_id=APP-<REDACTED>
build_id=BUILD-<REDACTED>
key_id=KEY-<REDACTED>
issuer_id=ISSUER-<REDACTED>
host=runner-<REDACTED>
log_path=/var/log/<REDACTED>/upload.log
state=processing
last_confirmed_at=<REDACTED>
「App Store Connectのアップロード制限後は再アップロードが必要か」という判断は、転送結果で決まります。
- 転送失敗、受付記録なし:同じタスクを重複させず、入力成果物を確認して再送信します。
- 転送受付済み、処理中:再送信せず、状態確認へ進みます。
- 処理完了、TestFlightで利用不可:署名、対象アプリ、処理結果を確認します。
- 状態不明:タスクを手動確認待ちに止め、無限ポーリングを解除します。
リモートMacの運用分離
リモートMacでは、SSH接続が切れても公開処理そのものが消えないよう、ターミナルの接続状態とRunnerの実行状態を分けます。アップロード成果物、状態ファイル、配信ログを同じ作業ディレクトリに置き、再接続時にタスクIDから再開できるようにしてください。
また、複数アプリで同じ再試行キューを共有しないことが重要です。アプリ、環境、公開段階ごとにキューを分けると、1つの制限が全プロジェクトへ波及しにくくなります。証明書やAPIキーの保管場所もプロジェクト単位で分離し、ログへ秘密情報を出力しないようにします。
リモートMacを継続的なiOS打ち上げ環境として使う場合は、Macレンタルの運用ポリシーも確認し、誰が接続し、どの成果物を残すかを決めておくと復旧時の確認が速くなります。開発環境そのものが必要なら、VpsMeshのMac環境を候補にできますが、長期的な高負荷運用や物理ポートが必要な作業では自前のMacが適する場合もあります。
06復旧判定用チェックリスト
次の項目を、実際のTestFlightビルドで順番に確認します。
- [ ] アップロード実行とAPI状態確認を別Jobまたは別状態として記録した
- [ ] タスクID、App ID、Build IDをログへ保存した
- [ ] 429などのHTTP応答、本文、ヘッダーを保存した
- [ ] 配信ログでバイナリ受付の有無を確認した
- [ ] 受付済みのビルドを自動再送信しない条件を追加した
- [ ] WebhookイベントをBuild IDへ関連付けた
- [ ] Webhook未着時の補償確認を有限処理にした
- [ ] 手動確認へ移す停止条件を用意した
- [ ] SSH切断後もRunnerと状態ファイルが残ることを確認した
- [ ] 実ビルドがTestFlightで利用可能になるところまで記録した
| 公開段階 | 成功とみなす証拠 | 失敗時の扱い |
|---|---|---|
| ビルド生成 | 期待する成果物とBuild ID | 成果物を作り直す |
| バイナリ送信 | TransporterまたはXcodeの受付ログ | 転送経路を調べる |
| API状態確認 | 対象Build IDと最新状態の一致 | リトライを抑制する |
| バックグラウンド処理 | 処理完了を示す状態 | 再送信せず待機・確認する |
| TestFlight確認 | 対象ビルドがテスト対象として選べる | 署名や処理結果を調べる |
| 運用方式 | 利点 | 欠点・回避策 |
|---|---|---|
| 現在の一括リトライ | 実装変更が少ない | 制限時に全段階が連鎖停止する |
| 低頻度の補償ポーリング | 既存API中心で移行しやすい | 停止条件と重複排除が必要です |
| Webhook中心 | 状態確認の常時呼び出しを抑えやすい | イベント遅延時の補償処理が必要です |
| アップロードと確認の分離 | 再送信事故を防ぎやすい | 状態管理の実装が増えます |
最終的には、現行方式をそのまま使うかどうかを、実ビルドの受け入れ結果で決めます。まずアップロードと状態確認を分離し、次に有限リトライとWebhookまたは補償確認を組み合わせてください。
自前のMacを常時稼働させる方式は、物理アクセス、長期の固定負荷、社内ネットワークとの直接接続が必要なら合理的です。ただし、購入費用、保守、電源、障害時の交換、単一ホストへの依存が負担になります。クラウド上の一般的なLinux環境ではXcodeとmacOS専用の署名工程を置けず、無理に構成すると公開直前だけ別環境へ成果物を移す手間も増えます。
一方、遠隔のMacを必要な期間だけ使う方式なら、常駐Runner、SSH切断後の継続処理、APIキーの分離を前提に、公開環境を切り出せます。短期の検証や複数アプリのリリース準備では、Macレンタルの選択肢を比較し、1回のTestFlight公開で復旧手順まで確認してから継続利用を判断するのが現実的です。