1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【GAS】LockServiceの待機限界は30秒じゃない?AIの回答を疑って1800秒実行の壁に挑戦

1
Last updated at Posted at 2026-03-31

前提

この記事は、Google Workspace Enterpriseを利用し、
2026年3月現在のAppsScriptを使っています。

※この記事は公式仕様の解説ではなく、実験ベースの挙動検証です。


この記事 ⇓ でLockServiceについて書いたとき、
Googleフォームで同時に大量送信されても踏ん張る!LockServiceで順番制御!try - catch - finally でバトンを繋げ!
そもそもwaitLock()って何秒までOKなんだろう?
6分の壁にぶち当たらなければ長くてもOK?
そんな疑問が生じ、chatGPTとGeminiに聞いてみた。

chatGPT:👉 waitLock() の最大は 30秒(30000ミリ秒)です
30秒を超える指定はエラーになります。
Gemini:実は、waitLock に指定できる最大時間は 30,000(30秒) と決まっています。
それ以上に設定しようとしても、GAS側で弾かれてしまうんです。

2人とも頑なに「waitLock()の最大は 30秒(30000ミリ秒)!それ以上はエラー!!」と主張するんだけど、リファレンスにはそんなこと書いてないし、ほんとにそうなん??と疑問に思ったのがきっかけ。

waitLockを30秒以上にする

まずは単純に、こんなのを作ってみた。
waitLockを31秒待ち、実行時間30秒で第2走者へバトンをパス。
これをスプレッドシートに作ったボタンに紐づけて、手動で約1秒間隔で2回実行。
30秒ルールがあるなら、エディタに書いたときとか保存時とか実行時とか何らかのエラーが出るはず。

function time_test(){
  Logger.log("開始したよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));

  var lock = LockService.getScriptLock();
  lock.waitLock(31000);      //31秒
  Logger.log("鍵をもらったよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
  Utilities.sleep(30000);
  lock.releaseLock();
  Logger.log("終了したよ! "+ Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
}
  

image.png

エディタに書いた時点でも何もエラー表示されないし、実行時もエラーにならない。

結論:普通にできるやん。
image.png

第1走者:
 開始と同時に鍵を取得して30秒後に終了
第2走者:
 開始の30秒後に鍵をもらってその30秒後に終了

ごくごく普通に予定どおりに終了した。
waitLock()の最大は 30秒 は少なくとも今回の検証環境では当てはまらず。
もしかしたらGoogleのかつてのデフォルト設定や推奨値がAIの学習データとして残っているのかもしれませんね。

もっと待機時間を伸ばしてみる

waitLock5分30秒待ち、処理も5分かかるやつを作って2回実行してみる。
第1走者が5分で完走後、第2走者にバトンが行くも、6分の壁でリタイア、と予想。

function time_test(){
  Logger.log("開始したよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
  var lock = LockService.getScriptLock();
  lock.waitLock(330000);      //★5分30秒待ち
    Logger.log("鍵をもらったよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    
  //合計5分の処理
  Utilities.sleep(30000);
    Logger.log("30秒経過:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
  Utilities.sleep(30000);
    Logger.log("60秒経過:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
  Utilities.sleep(240000);    
    Logger.log("300秒経過:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    
  lock.releaseLock();
  Logger.log("ロック解除したよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
}

あれ?普通に第2走者も完走した。
総実行時間約10分。
6分の壁、どこ行った?
待ち時間は6分のカウント外?
それともWorkspaceの30分ルールが適用?
image.png

30分ルールを除外するため、トリガーから実行

インストールトリガーを使えば必ず6分でタイムアウトする!と力説するchatGPTとGeminiを信じてトリガーを使うことにした。

以下のコードを使い、インストールトリガーで「スプレッドシートから」「編集時」にして、適当なセルに「1」を入れる × 2回
第2走者がどこでコケるかを観察。AIが正しければ30秒経過の前で力尽きるはず。

function time_test(){
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート1");
  const value = sheet.getActiveCell().getValue(); //アクティブセルの値を取得
  if(value != ""){    //アクティブセルの値が空欄じゃなければ以下を実行
    Logger.log("開始したよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    var lock = LockService.getScriptLock();
    lock.waitLock(330000);      //★5分30秒待ち
      Logger.log("鍵をもらったよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));

    Utilities.sleep(30000);
      Logger.log("30秒経過:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    Utilities.sleep(30000);
      Logger.log("60秒経過:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    Utilities.sleep(240000);    
      Logger.log("300秒経過:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
      
    lock.releaseLock();
    Logger.log("ロック解除したよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
  }
}

あれ?第2走者、完走しちゃったよ。
実行時間 600.963秒(約10分!)
image.png

ここで再度chatGPTとGeminiに聞いてみた。
「Workspaceでもトリガーは6分制限だよね?実行時間10分なのはどうして?」

  • chatGPT:インストール型トリガーでも「6分制限」はちゃんと適用されています。
    今回「600秒(10分)で完走したように見えた」のは、少しトリッキーな理由です。
    👉 waitLock中は「ほぼ実行時間にカウントされない」
  • Gemini:「Workspaceアカウントなら30分まで大丈夫でしょ?」と思われがちですが、実はボタンクリックやフォーム送信トリガーで動くときは、Workspaceでも『6分の壁』が適用されます。
    Google Workspace(有料版)を使っていても、この「裏側で勝手に動く系」の処理については、一般ユーザーと同じ制限であることが多いので注意が必要です。
    「待機時間は寿命に含まれない」ことが確定しました。待機で6分使い、さらに実行で6分使っています。

2人とも口をそろえて待機時間はカウント外って言ってるけど、いやいやいやちょっと待って。
本当に、本当に、トリガーだと6分制限になるの?
寄り道になるけど、これは確認したほうがいいよね。


シンプルトリガーならどうだ!

シンプルトリガーは実行時間30秒までの制限。
このGASの実行時間は約25秒なので
これで第2走者は鍵を受け取って5秒後にタイムアウトするはず。

function onEdit(e){
  Logger.log("開始したよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));

  var lock = LockService.getScriptLock();
  lock.waitLock(30000);      //30秒
    Logger.log("鍵をもらったよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    
  Utilities.sleep(25000);
  lock.releaseLock();
   Logger.log("終了したよ! "+ Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
}

こっちは開始後30秒で第2走者、無事死亡。
image.png

待機時間も制限時間に含まれるってことだよな。

やっぱインストールトリガーもWorkspaceの30分ルール適用説が濃厚。


30分ルートにチャレンジ

すごくしんどいけど、GASの最後のほうにアディショナルタイムとして合計31分になるようにしてインストールトリガーで実行。

function time_test(){
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート1");
  const value = sheet.getActiveCell().getValue(); //アクティブセルの値を取得
  if(value != ""){    //アクティブセルの値が空欄じゃなければ以下を実行
    Logger.log("開始したよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    var lock = LockService.getScriptLock();
    lock.waitLock(370000);      //★6分待ち
      Logger.log("鍵をもらったよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));

    Utilities.sleep(30000);
      Logger.log("30秒経過:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    Utilities.sleep(30000);
      Logger.log("60秒経過:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    Utilities.sleep(300000);    
      Logger.log("300秒経過:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
      
    lock.releaseLock();
    Logger.log("ロック解除したよ:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));

    Utilities.sleep(5*60*1000);    
       Logger.log("アディショナルタイム5分:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    Utilities.sleep(5*60*1000);    
       Logger.log("アディショナルタイム5分:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    Utilities.sleep(5*60*1000);    
       Logger.log("アディショナルタイム5分:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    Utilities.sleep(5*60*1000);    
       Logger.log("アディショナルタイム5分:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
    Utilities.sleep(5*60*1000);    
       Logger.log("アディショナルタイム5分:" + Utilities.formatDate(new Date(),"JST","HH:mm:ss"));
  }
  
}

5分経過後にロックを解除し第2走者が再開し、その後、25分のアディショナルタイム。
sleepの実行時間は5分以上設定するとエラーになるので(ここは明確に時間制限あり)、5分のsleepを5回接続。(forを使うよりコピペしたほうが楽だっただけ)

うまくいけばロックを解除後、何回めかのアディショナルタイムで力尽きるはず。

image.png

まずは第1走者。
5分経過後にロック解除し、その後5回目のアディショナルタイムを待たずにタイムアウト。
実行時間は1801.862秒。(約30分)

そして1秒遅れでスタートした第2走者も、開始5分後に第1走者から鍵を受け取って走り出し、1802.158秒後にタイムアウト。
アディショナルタイムは第1走者より1つ少なくなった。

トリガー使用であってもWorkspaceの場合は30分制限が適用されているってことだよね。

※今回の検証環境はWorkspace Business以上です。一般の環境の方は30分ではなく6分です。

結論

  • waitLockの引数に明確な上限はない。(ただし実行時間制限に依存)
  • 待機時間も実行時間にカウントされる。
  • シンプルトリガーの実行時間制限は30秒、Workspaceの実行時間制限はインストールトリガー使用時でも30分。

AIの30秒説はあっさり覆されたわけだけど、学習時のデータの影響かもね。
もしかしたら古い推奨値やサンプルコードの30秒と混同しちゃってる可能性もあるかも。
この記事が公開されてもし学習データに入ることがあったら、AIも心(?)を入れ替えるかもしれませんね。


ここまで書いて、じゃあ 鍵を返さないままエラーやタイムアウトしたら? って新たな疑問が出てきたので次回はそれについて書いてみようと思います。(近日公開予定)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?