ADVERTISEMENT

【Googleスプレッドシート】Apps Scriptで連続して実行が止まる時の対処!タイムアウト原因の切り分け

【Googleスプレッドシート】Apps Scriptで連続して実行が止まる時の対処!タイムアウト原因の切り分け
🛡️ 超解決

Apps Scriptで作った自動処理が途中で止まってしまい、何度も再実行を繰り返していませんか?その原因の多くは、スクリプトの実行時間制限や割り当て上限に達したことによる強制停止です。本記事では、タイムアウトが発生する原因を切り分ける方法と、連続実行を最後まで完了させるための具体的な対策手順を詳しく解説します。

タイムアウトの原因は単純なスクリプトの長さだけでなく、処理の重さや外部APIの応答待ち、トリガーの重複など多岐にわたります。これらの原因を一つずつ切り分けることで、適切な対策を打てるようになります。この記事を読み終えれば、Apps Scriptの長時間実行を安定して動かせるようになるでしょう。

【要点】Apps Scriptの連続実行タイムアウトを防ぐ3つの対策

  • 実行時間の分割とバッチ処理: 長時間のループを分割し、forループの途中で処理を区切って複数回のトリガー呼び出しに分散させます。
  • トリガーの重複防止と割り当て制限の確認: 時限トリガーが重複して起動しないように制御し、スクリプトエディタの「割り当て」で現在の消費量を確認します。
  • CacheServiceやPropertiesServiceの活用: 処理の途中経過を保存して、次の実行時に再開できるようにすることで、トータルのタイムアウトを回避します。

ADVERTISEMENT

Apps Scriptのタイムアウトが起きる主な原因

Apps Scriptには、1回の実行が6分を超えると強制停止される「実行時間制限」があります。また、1日あたりのトリガー合計実行時間や外部API呼び出し回数にも割り当て制限があります。連続実行が止まるのは、これらの制限に達したことがほとんどです。具体的には、次のような原因が考えられます。

  • 1回のスクリプトが6分以上かかっている
  • スプレッドシートの行数が多く、ループ処理に時間がかかっている
  • トリガーが重複して設定され、同時に複数の実行が発生している
  • 外部API(URL Fetchなど)の応答待ちで時間を消費している
  • 日々の割り当て(例:メール送信100通/日)を超えてエラーになっている

これらの原因を切り分けるためには、スクリプト内にログ出力を仕込み、どこで時間がかかっているかを特定することが重要です。

タイムアウトを防ぐ具体的な対策手順

対策1: 実行時間を分割するバッチ処理

  1. 処理するデータを複数のバッチに分割する設計を行う
    例として、全データを一度に処理するのではなく、100行ずつ処理するように分割します。スクリプト内で「何行目まで処理したか」というカウンターをスプレッドシートのセルやPropertiesServiceに保存します。
  2. 途中経過を保存して、次回実行時に続きから処理できるようにする
    Script Propertiesに「最後に処理した行番号」を保存します。次回のトリガー起動時にその値を使って次のバッチから開始します。これにより、1回の実行時間を6分以内に収めながら全体を完了させます。
  3. トリガーを複数回呼び出して連続実行させる
    1回のトリガーで全データを処理せず、トリガーを一定間隔(例えば1分おき)で設定し、分割したバッチを順次実行します。トリガーのオーバーラップに注意する必要があります。

対策2: トリガーの重複防止と割り当て制限の確認

  1. 現在設定されているトリガーを確認し、不要なものを削除する
    スクリプトエディタの「トリガー」メニューを開き、誤って重複して登録したトリガーがないか確認します。特に「時間主導型」のトリガーは複数あると同時に起動する可能性があります。
  2. トリガーの実行間隔を調整してオーバーラップを防ぐ
    バッチ処理のトリガーは、前回の実行が終わってから次のトリガーが起動するように、間隔を十分に空けます。例えば5分間隔で設定しておけば、6分以内の処理なら重複しません。
  3. スクリプトエディタの「割り当て」を確認し、残り容量を把握する
    「表示」→「割り当て」から、現在の実行時間やメール送信数などの使用量を確認します。これにより、制限に近づいているかどうかを事前に把握できます。

対策3: CacheServiceやPropertiesServiceを活用した状態管理

  1. 処理の途中状態を保存するためのサービスを選ぶ
    CacheServiceは一時保存向きですが、PropertiesService(Script Properties)は永続的に保存できます。バッチ処理の場合は、PropertiesServiceを使って「最終処理行」を保存します。
  2. 保存したデータを読み込んで処理を再開するロジックを実装する
    スクリプトの先頭でPropertiesService.getScriptProperties()から前回の保存値を取得し、その行からループを開始します。処理が完了したら保存値を更新します。
  3. エラー発生時のリカバリー処理も組み込む
    もしスクリプトが途中でエラーで止まった場合でも、PropertiesServiceに保存された値はそのままなので、トリガーが次に起動したときに続きから再開できます。これにより、全体的な処理の完遂率が向上します。

よくあるタイムアウトの症状とその対処法

ループ処理の途中でスクリプトが止まる

for文やwhile文のループ内で、1ループあたりの処理に時間がかかりすぎると、6分の制限に引っかかって強制停止します。この場合は、ループを分割するバッチ処理が有効です。また、ループ内で大量のスプレッドシート操作(getRangeやsetValue)を行っていると、書き込み時間が累積するので、配列を使って一度に書き込む方法に切り替えることも効果的です。

トリガーが重複して実行され、複数のスクリプトが同時に動く

「時間主導型」トリガーを複数設定していると、意図せず同時に起動することがあります。これにより、スクリプト同士が干渉したり、割り当て制限を一気に消費してしまいます。解決策としては、トリガーを1つだけにし、バッチ処理の間隔を調整することです。また、スクリプト内で「現在実行中のトリガーが他にないか」をチェックする排他制御を入れる方法もあります。

外部API(URL Fetch)の応答待ちでタイムアウト

外部APIへのリクエストが遅い場合、その待ち時間も実行時間にカウントされます。対策として、URL Fetchのタイムアウト設定(setTimeout)を適切に設定し、応答がない場合はリトライする回数を制限します。また、バッチ処理の1単位に含めるAPI呼び出し数を減らして、1回の実行時間を短くすることも有効です。

ADVERTISEMENT

各対策方法の比較

対策方法 メリット デメリット 適したケース
バッチ処理+PropertiesService 大規模データでも確実に処理できる スクリプトの設計がやや複雑になる 大量の行を順次処理する必要がある場合
トリガーの最適化(重複防止) ほぼコード変更なしで即効性がある 根本的な処理時間短縮にはならない すでにトリガーが複数ある場合や、タイムアウトがまれにしか起きない場合
配列一括書き込みによる高速化 ループ内のsetValueを減らして実行時間を短縮できる スプレッドシートの構造によっては適用しづらい セルへの書き込みがボトルネックになっている場合
URL Fetchのタイムアウト設定とリトライ制限 外部APIの遅延による待ち時間を抑制できる APIの応答次第ではデータ欠損リスクがある 外部APIを頻繁に呼び出すスクリプト

まとめ

Apps Scriptが連続実行で止まる原因は、主に実行時間制限や割り当て制限によるものです。本記事で紹介したバッチ処理とPropertiesServiceを使った状態保存、トリガーの重複防止、配列一括書き込みなどの対策を組み合わせることで、タイムアウトを回避しながら大量データを安定して処理できるようになります。まずはスクリプトエディタの「割り当て」で現在の使用量を確認し、自分のスクリプトがどの制限に近づいているか把握することから始めてみてください。それに合わせて適切な対策を選べば、処理が止まるストレスから解放されるでしょう。


ADVERTISEMENT

この記事の監修者
✍️

超解決 第一編集部

疑問解決ポータル「超解決」の編集チーム。正確な検証と、現場視点での伝わりやすい解説を心がけています。