◉GEMINI LABEN
●3.8 FLASH — 3.7 Flash は 10/08 に非推奨に。旧モデルへの要求は 3.8 Flash へ自動で回されます●NANO 2.1 — gemini-nano-banana-2.1 が GA。gemini-3.1-flash-image は非推奨で停止日は未発表●DEADLINE — veo-3.1 の preview と gemini-omni-flash-preview は 10/22、Deep Research エージェントは 10/23 に停止(残り12〜13日)●Q&A — Gemini CLI でサブエージェントが MAX_TURNS で止まっても成功と報告される、という報告が出ています●TTS/LIVE — 2.5 系の音声・TTS 系プレビューは 11/17 に停止、残り38日●NEW — 停止日のない非推奨をどう扱うか。画像モデルの移行先を3つの条件で選び直す●3.8 FLASH — 3.7 Flash は 10/08 に非推奨に。旧モデルへの要求は 3.8 Flash へ自動で回されます●NANO 2.1 — gemini-nano-banana-2.1 が GA。gemini-3.1-flash-image は非推奨で停止日は未発表●DEADLINE — veo-3.1 の preview と gemini-omni-flash-preview は 10/22、Deep Research エージェントは 10/23 に停止(残り12〜13日)●Q&A — Gemini CLI でサブエージェントが MAX_TURNS で止まっても成功と報告される、という報告が出ています●TTS/LIVE — 2.5 系の音声・TTS 系プレビューは 11/17 に停止、残り38日●NEW — 停止日のない非推奨をどう扱うか。画像モデルの移行先を3つの条件で選び直す
記事一覧/Workspace 連携
◧ Workspace 連携/2026-06-29上級

Apps Script の時間主導型トリガーが静かに枯渇する — Gemini 自動化を一本のディスパッチャに束ねる

Apps Script の時間主導型トリガーは1ユーザー20本・1日の合計実行時間にも上限があります。Gemini 自動化を増やすたびに無音で止まる問題を、単一ディスパッチャとスケジュール表とハートビートで解く実装を示します。

gemini117apps-script11google-workspace7automation36trigger

✦ プレミアム記事

「昨日まで動いていた自動返信が、エラーも出ないまま止まっていた」。個人開発で複数の Google Workspace 自動化を運用していると、この無音の停止に何度か出くわします。私自身、壁紙アプリのレビュー返信の下書き生成と、問い合わせメールの要約と、売上シートの集計を、それぞれ別の時間主導型トリガーで回していた時期に、ある日まとめて止まりました。実行ログを開いても、失敗の記録すら残っていません。

原因はコードのバグではなく、Apps Script のトリガー資源を使い切っていたことでした。トリガーは無限に増やせる前提で設計しがちですが、実際にはかなり手前に天井があります。ここでは、その天井の正体を数字で押さえたうえで、ジョブごとにトリガーを乱立させる構成を、5分間隔の単一ディスパッチャに束ね直す実装を示します。

トリガーは「数」と「時間」の二重の上限で枯れる

多くの人が見落とすのは、トリガーの制約が一つではないことです。枯渇は別々の二つの資源で起こります。

ひとつは トリガーの本数 です。Apps Script では1ユーザーあたり1スクリプトに作成できるトリガーが20本までと決まっています。自動化を「1機能 = 1トリガー」で増やしていくと、20本目で This script has too many triggers が出て、それ以降の ScriptApp.newTrigger が静かに失敗します。

もうひとつは 1日あたりのトリガー合計実行時間 です。無料の gmail.com アカウントではトリガーの累積実行時間がおおむね1日90分、Google Workspace の有償アカウントでも6時間で頭打ちになります。Gemini API への呼び出しはネットワーク待ちで1回あたり数秒かかるため、ジョブが増えるとこの時間枠は思ったより速く溶けます。枠を使い切ると、その日の残りのトリガーは 通知もなく発火しなくなります。

次の表は、運用設計で意識すべき主要な上限です。アカウント種別で数字が変わる点に注意してください。

資源無料(gmail.com)Workspace(有償)枯渇時の症状
トリガー本数 / ユーザー / スクリプト2020newTrigger が失敗
トリガー合計実行時間 / 日約90分約6時間発火が無音で停止
1実行あたりの最大時間6分30分途中で強制終了
UrlFetch 呼び出し / 日20,000100,000fetch が例外

ここで効いてくるのは、1機能ごとにトリガーを立てる設計が、両方の上限を同時に圧迫する という点です。本数を消費し、かつ各トリガーの起動オーバーヘッドと空振りチェックが実行時間枠を削ります。私が止まったときも、本数こそ20本未満でしたが、5分間隔のトリガーを3本回していたために、合計実行時間の枠を昼前に使い切っていました。

1機能=1トリガーをやめ、単一ディスパッチャに束ねる

解決の骨格はシンプルです。トリガーは ただ一本 だけ作り、それを5分おきに発火させます。その一本が「いまどのジョブを動かすべきか」をスケジュール表から判断し、期限の来たジョブだけを順に実行します。トリガーの本数は常に1、実行時間枠も1本ぶんに収まります。

まずジョブの定義です。各ジョブは「実行間隔(分)」と「実体の関数」を持つだけにします。

// ジョブ定義。intervalMin ごとに fn を1回走らせたい、という宣言だけを持つ
const JOBS = [
  { id: 'reviewReplyDraft', intervalMin: 15, fn: runReviewReplyDraft },
  { id: 'inquirySummary',   intervalMin: 30, fn: runInquirySummary },
  { id: 'salesRollup',      intervalMin: 60, fn: runSalesRollup },
];
 
// 5分間隔のトリガーから呼ばれる唯一の入口
function dispatch() {
  const lock = LockService.getScriptLock();
  // 前回の実行が長引いて重なるのを防ぐ。取れなければ今回は黙って降りる
  if (!lock.tryLock(1000)) return;
  try {
    const props = PropertiesService.getScriptProperties();
    const now = Date.now();
    const runStart = now;
    const RUN_BUDGET_MS = 4 * 60 * 1000; // 1実行6分の手前で必ず抜ける安全弁
 
    for (const job of JOBS) {
      if (Date.now() - runStart > RUN_BUDGET_MS) break; // 時間枠を守る
      const lastKey = 'last_' + job.id;
      const last = Number(props.getProperty(lastKey) || 0);
      if (now - last < job.intervalMin * 60 * 1000) continue; // まだ期限前
      try {
        job.fn();
        props.setProperty(lastKey, String(now)); // 成功時のみ前進
      } catch (e) {
        console.error('job failed: ' + job.id + ' / ' + e);
        // 失敗時は last を更新しない = 次回再試行される(冪等性は各 fn 側で担保)
      }
    }
    props.setProperty('heartbeat', String(now)); // 生存記録
  } finally {
    lock.releaseLock();
  }
}

ポイントは3つあります。ひとつ目は RUN_BUDGET_MS で、6分の実行上限に達する前に必ずループを抜けることです。残ったジョブは次の5分後のディスパッチで拾われます。ふたつ目は LockService による二重起動の防止で、前回が長引いて次の発火と重なっても、片方が静かに降りるので同じジョブが並行実行されません。みっつ目は、成功したときだけ last_ を更新することです。失敗時は時刻を進めないので、次の周回で自動的に再試行されます。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦Gemini 自動化を増やすたびトリガーが無音で止まる原因を、20本上限と1日90分の実行時間枠という2つの数字で説明できるようになる
✦ジョブごとに別トリガーを立てる構成を、5分間隔の単一ディスパッチャとスケジュール表に置き換える動くコードを手に入れられる
✦止まったことに気づくためのハートビートと外部監視、LockService による二重起動防止まで含めた運用設計を実装できる
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Gemini Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

関連記事

◧ Workspace 連携2026-07-16
=GEMINI() を420行に貼って気づいたこと — カスタム関数をやめ、値で書き戻すまでの実測
Sheets のカスタム関数から Gemini を呼ぶ構成は、動いた瞬間がいちばん美しく、そこから伸びません。30秒の壁・制御できない再計算・書き戻せない結果という3つの性質を実測で確かめ、値で書き戻す設計へ移すまでの手順とコードを残します。
◧ Workspace 連携2026-05-27
Google Play 多言語レビュー返信を Gemini と作る — 11 言語の温度感を維持する運用設計
Google Play のレビューに、日本語・英語・繁体字・韓国語・タイ語・イタリア語・ロシア語・ペルシャ語・ウクライナ語・ポーランド語の 11 言語で返信し続けるための運用ルールと、Gemini に何を任せて何を任せないかの線引きを、実際に 2 セッション 71 件返信した記録から書きます。
◧ Workspace 連携2026-10-03
Sheets から呼ぶ Gemini の月額を、年末の値上げ日をまたいで Apps Script で割り出す
スプレッドシートから Gemini API を呼んでいる方へ。呼び出しごとのトークン数を台帳タブに残し、2026年12月31日で終わる導入価格と2027年1月1日からの標準価格の二段で月額を見積もる Apps Script を、動かした出力つきで書き残します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます