目次
Googleスプレッドシートで外部APIからデータを定期取得する処理を組んでいると、時々「突然スクリプトが止まった」という連絡が届くことがあります。ログを確認してみると、API側の瞬間的な高負荷による503 Service Unavailableや、ネットワークの揺らぎによるタイムアウトエラーが発生しているケースが少なくありません。相手側のサーバーが完全に落ちているわけではなく、単にその瞬間のリクエストだけが失敗したという場合、手動で再実行すれば何事もなかったかのように動きます。しかし、夜間トリガーや定期実行の処理でいちいち人間が監視して再実行ボタンを押すのは現実的ではありません。こうした一時的なエラーに対処するためには、エラーが発生した際に少し時間を置いてから自動でリトライを行うロジックをGAS側に入れておく必要があります。
外部APIの瞬断や503エラーで処理が止まる現場の課題
スプレッドシートをダッシュボードとして運用したり、顧客データや商品情報を外部のSaaSから取得してシートに転記する業務では、UrlFetchAppを用いてAPIを呼び出すのが一般的です。開発時や単体テストの段階では何の問題もなくレスポンスが返ってきていたとしても、実際の運用を始めるとエラーは回避できません。例えば、毎朝9時にAPIを実行するトリガーをセットしている場合、相手方のサービスもアクセス集中によって一時的に処理が重くなり、HTTP 503エラーを返すことがあります。また、クラウドインフラのメンテナンスや一時的なネットワーク疎通障害によって、数秒間だけ接続が切れるという現象も珍しくありません。
何も対策をしていない場合、GASの標準の動きでは例外が発生した時点でスクリプト全体の実行が停止します。スプレッドシート上には前日の古いデータが残ったままになり、後続の計算やメール送信処理が不完全な状態で終わってしまいます。さらに悪いことに、エラー通知がメールで届くだけで処理自体は途中で失敗しているため、担当者が朝出社してから手動でスクリプトを再実行しなければならず、業務の開始が遅れてしまうというトラブルにつながります。
ここで重要なのは、「失敗したリクエストのすべてが致命的なバグではない」ということです。システム障害ではなく単なる瞬断や一時的なオーバーロードであれば、数秒から数分待ってからもう一度アクセスするだけで正常にデータを取得できます。この「少し待って再実行する」というアプローチを自動化するのが、リトライ処理の役割です。特にGASで外部システムとの連携を行う際には、通信エラーを前提とした堅牢な設計にしておくことが現場での保守手間を大幅に減らすポイントになります。
一定時間あけて再試行するUrlFetchのリトライ処理
具体的にGASでリトライ処理を構築する際、どのように実装すればよいかを解説します。UrlFetchApp.fetchをそのまま呼び出すのではなく、ループ処理と例外捕獲(try…catch)、そしてウェイト処理(Utilities.sleep)を組み合わせたラッパー関数を作成するのが最もシンプルかつ効果的な方法です。
以下に示すコードは、指定した回数だけAPI呼び出しを試み、失敗した場合には待機時間を段階的に延ばしながら再実行する処理です。
function fetchWithRetry(url, opt, times) {
for (let i = 0; i < times; i++) {
try {
return UrlFetchApp.fetch(url, opt);
} catch (e) {
Utilities.sleep(1000 * (i + 1));
}
}
throw new Error("UrlFetch failed");
}
このコードは、外部API呼び出しで一時的なネットワークエラーやサーバーエラーが発生したときに使います。基本となる使い方は、従来の UrlFetchApp.fetch(url, opt) をそのまま fetchWithRetry(url, opt, 3) のように置き換えるだけです。
ここで注意すべき点、つまり「実務でずれる点」は、待機時間の長さと回数のバランスです。単に定数で Utilities.sleep(1000) と固定して即座にリトライを繰り返すと、APIサーバー側が負荷で苦しんでいるときにさらにリクエストを叩き込むことになり、余計にエラーが解消されにくくなります。上記の例では 1000 * (i + 1) とすることで、1回目の失敗後は1秒、2回目の失敗後は2秒と、回数を重ねるごとに待機時間を少しずつ延ばしています。これをいわゆるバックオフ戦略と呼びます。
この設計によって回避できるトラブルは、瞬間的なスパイクエラーによる処理中断です。ただし、相手側の認証エラー(HTTP 401)やリクエストの書き方が間違っている場合(HTTP 400)など、何度リトライしても絶対に成功しないエラーに対しても同様に再試行を行ってしまうという課題が生じます。この問題の回避方法については、レスポンスコードの判定ルールを意識することが不可欠になります。
例外処理とステータスコードで知っておくべき挙動の違い
GASにおけるUrlFetchAppの挙動で混乱しやすいのが、HTTPステータスコードに対する例外の発生有無です。標準の設定では、UrlFetchApp.fetchはステータスコードが4xxや5xxなどのエラーを示す値だった場合、GAS自体の例外(Exception)を発生させてスクリプトを強制終了させます。つまり、try...catch の catch ブロックに飛ぶのは、通信自体のタイムアウトやドメイン解決失敗のほか、404 Not Foundや500 Internal Server ErrorなどのHTTPエラーレスポンスが返ってきたときです。
しかし、オプションに muteHttpExceptions: true を指定すると、挙動が大きく変化します。このオプションを有効にすると、たとえ503エラーや404エラーが返ってきても例外は投げられず、通常通り HTTPResponse オブジェクトが返されます。この場合、try...catch の catch ブロックには入らないため、上記のシンプルな fetchWithRetry のままだと「503エラーが返ってきたのに成功したとみなしてループを抜けてしまう」という不具合が発生します。
実務でより精密なコントロールを行いたい場合は、muteHttpExceptions: true を設定した上で、取得したレスポンスのステータスコードを response.getResponseCode() で取得し、コードが 200〜299 以外の場合に意図的に例外を投げるか、またはリトライのループを継続するロジックを組む必要があります。一時的なエラー(502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout)のみをリトライ対象とし、恒久的なエラー(401 Unauthorized, 403 Forbidden, 404 Not Found)のときは即座にリトライを諦めてエラー終了させる、といった振り分けを行うことで、無駄なリトライ時間を削減し、APIの利用制限に引っかかるリスクを軽減できます。
GASの実行時間制限とバックオフ時間のバランス調整
GASでリトライ処理を組み込む際に絶対に無視できないのが、GAS特有の実行時間制限です。無料のGoogleアカウントの場合、1回のスクリプト実行時間は最長6分(360秒)までに制限されています。Workspaceアカウントであっても15分です。リトライ処理で待機時間を長く設定しすぎると、この制限時間に達してしまい、スプレッドシート全体の処理が不完全なまま強制終了する危険性があります。
例えば、大量の行を1行ずつループ処理しながら外部APIを呼び出す構造になっているスクリプトで、1リクエストあたり5回のリトライと毎回数十秒のウェイトを挟むと、数回の通信失敗であっという間に6分が経過してしまいます。これでは、リトライ処理を追加したことが原因でスクリプト全体が制限時間オーバーでコケるという本末転倒な事態に陥ります。
この問題を回避するための調整案として、以下の工夫が求められます。まず、リトライ回数は原則として2〜3回程度にとどめることです。多くの通信障害は1〜2回の再試行(数秒の待機)で復旧するか、あるいは数分以上ダウンし続けるかのどちらかです。3回やってダメな場合は、それ以上その場で待っても解決しない可能性が高いため、早々に諦めてエラーを出力する方が安全です。
次に、ウェイトの合計時間を考慮したスクリプト設計を行うことです。API呼び出しが複数回ある場合は、単に個別の通信をリトライするだけでなく、スプレッドシート側で処理済みのインデックス(どこまで処理が終わったか)をPropertiesServiceなどに保持しておき、エラーで終了したとしても次回トリガー実行時に途中から再開できるようにするといった設計パターンを取り入れるのが実務では極めて有効です。
現場運用で役立つログ出力と通知の設計手法
リトライ処理を入れて自動で復旧できるようにしたとしても、「内部で何が起きていたのか」を後から追跡できるようにログを残しておくことは、業務自動化の保守において非常に重要です。静かに裏でリトライが成功していると、実は外部APIの仕様変更やパフォーマンス悪化が始まっていることに気付かず、ある日突然完全に動かなくなってから大騒ぎになるケースがあるためです。
リトライが走った際には、Logger.log や console.warn を使って、「何回目のリトライであるか」「発生したエラー内容またはステータスコード」「待機した時間」を記録しておくべきです。後からGASの実行数ログやCloud Loggingで確認したときに、特定の時間帯だけリトライが多発しているといった傾向を把握できるようになります。
また、リトライを規定回数(例えば3回)行ったにもかかわらず成功しなかった場合は、最終的に明確なエラーを発生させ(throw new Error)、管理者にメールやチャットツールで通知が飛ぶように工夫します。単にエラーで落とすだけでなく、「〇〇のAPI接続で3回リトライしましたが503エラーのため失敗しました。スプレッドシートの〇〇行目まで処理完了しています」といった詳細な文面を添えて通知することで、障害切り分けの時間を劇的に短縮できます。
GAS UrlFetch リトライの仕組みを正しく導入することは、単にコードを動かすだけでなく、システムトラブル時の人間側の運用負担を最小限に抑え、Googleスプレッドシートを使った業務自動化の信頼性を担保するための必須の工夫と言えます。

