GASの6分実行時間制限を
回避する3つの実装パターン

大量データ処理でスクリプトが途中で止まってしまう問題を、分割実行・時間主導トリガー・LockServiceの組み合わせで解決する方法を解説します。

|対象: GAS / 実行時間制限 / トリガー

Table of Contents

なぜ6分で処理が止まるのか

Google Apps Scriptには、通常のGoogleアカウントで1回の実行につき最大6分、Google Workspaceアカウントでも最大30分という実行時間の上限が設けられています。 大量の行を処理するスクリプトや、外部APIへの多数のリクエストを行う処理では、この時間内に終わらずExceeded maximum execution timeエラーで途中終了してしまうことがあります。

パターン1:分割実行でカーソルを保持する

処理開始からの経過時間を計測し、一定時間(余裕を持って5分程度)を超えたら処理を中断します。 どこまで処理したかをPropertiesServiceに保存しておき、次回の実行時にはその続きから処理を再開します。

function processLargeDataJob() {
  const startTime = new Date().getTime();
  const maxRunTimeMs = 5 * 60 * 1000; // 5分で打ち切り

  const props = PropertiesService.getScriptProperties();
  let cursor = Number(props.getProperty("processCursor") || 0);

  const sheet = SpreadsheetApp.getActive().getSheetByName("処理対象");
  const data = sheet.getDataRange().getValues();

  while (cursor < data.length) {
    processRow(data[cursor]);
    cursor++;

    if (new Date().getTime() - startTime > maxRunTimeMs) {
      props.setProperty("processCursor", String(cursor));
      scheduleNextRun();
      return;
    }
  }

  props.deleteProperty("processCursor");
}

function processRow(row) {
  // 1行あたりの処理内容
}

パターン2:時間主導トリガーで自動的に再開する

処理が途中で終わった場合、自分自身を短い間隔で再度呼び出すトリガーを設定します。 既存の同名トリガーを削除してから再登録することで、トリガーが重複して増え続けるのを防ぎます。

function scheduleNextRun() {
  ScriptApp.getProjectTriggers().forEach((trigger) => {
    if (trigger.getHandlerFunction() === "processLargeDataJob") {
      ScriptApp.deleteTrigger(trigger);
    }
  });

  ScriptApp.newTrigger("processLargeDataJob")
    .timeBased()
    .after(1000) // 1秒後に再実行
    .create();
}

パターン3:LockServiceで多重実行を防ぐ

トリガーの実行タイミングが重なると、同じ処理が並行して動いてしまうことがあります。LockServiceでロックを取得し、既に実行中の場合は処理をスキップするようにします。

function processLargeDataJobSafe() {
  const lock = LockService.getScriptLock();

  if (!lock.tryLock(5000)) {
    Logger.log("既に実行中のためスキップします");
    return;
  }

  try {
    processLargeDataJob();
  } finally {
    lock.releaseLock();
  }
}

3つを組み合わせた実装

実務では、分割実行の関数をLockServiceでラップした上で、時間主導トリガーから呼び出す構成にします。 これにより「途中で切れても続きから再開できる」「同時に2つ動いてデータが壊れることもない」処理が実現できます。

分割実行

6分の壁を意識してカーソルを保存・再開する

時間主導トリガー

処理の続きを自動的に呼び出す

LockService

同じ処理が二重に走るのを防ぐ

実務での注意点

1. 打ち切り時間には余裕を持たせる

6分ぎりぎりまで粘ると、後処理やトリガー登録の途中でタイムアウトする恐れがあります。5分前後で余裕を持って打ち切るのが安全です。

2. トリガーの上限にも注意

1つのスクリプトで作成できるトリガー数には上限があります。再登録の際は必ず既存のトリガーを削除してから作り直す実装にしましょう。

3. カーソル位置の整合性を保つ

処理対象のデータが実行中に増減すると、カーソル位置がずれる可能性があります。IDなど不変のキーを基準に処理済み・未処理を判定する設計にすると安定します。

まとめ

GASの6分制限は仕様上避けられませんが、分割実行・時間主導トリガー・LockServiceを組み合わせることで、 見かけ上は長時間の処理を安全に完了させることができます。大量データを扱う業務システムほど、この設計が重要になります。

よくある質問

Google Apps Scriptには、通常のGoogleアカウントで1回のスクリプト実行につき最大6分という制限が設けられています。Google Workspaceアカウントでも上限は最大30分までで、それ以上長く動かし続けることはできません。

1回の実行を6分未満の単位に分割し、どこまで処理したかをPropertiesServiceに記録しておきます。次の実行では続きから再開することで、見かけ上は長時間の処理を完了させられます。

処理開始時刻を記録し、経過時間が一定の閾値(例えば5分)を超えたら処理を中断してカーソル位置を保存し、時間主導トリガーで自分自身を再度呼び出す、という仕組みを組み合わせます。

トリガーの実行タイミングが重なると、同じジョブが並行して動いてしまう場合があります。LockServiceでロックを取得し、既に実行中であれば処理をスキップするようにすることで防げます。

大量行のデータ処理、外部APIへの大量リクエスト、多数のファイル生成やメール送信など、1件あたりの処理時間は短いが件数が多く合計時間が6分を超えるケースに向いています。

GAS開発・業務Webシステムを
相談する。

大量データ処理や長時間バッチが必要な業務システムも、設計から実装までご相談いただけます。

GAS開発の対応範囲を見る