Google Apps Script(GAS)はスプレッドシート自動化に非常に便利ですが、実行時間が最大6分という制限があります。
今回、APIを呼び出してデータを取得し、スプレッドシートへ転記する処理を毎日実行していました。しかしAPI応答が遅く、合計で6分以上かかる状態になり、処理が不安定に。タイムアウト寸前、もしくは失敗することが発生していました。
そこで、重い処理をCloud Run Functionsへ移行し、安定化させました。
この記事ではその具体的なGASからCloud Run Functionsへの移行の方法を紹介します!
今回の要件と課題
要件は以下です。
- APIを呼び出し
- 取得データをスプレッドシートへ転記
- 毎日自動実行
- 既存のGASコード資産を可能な限り活用したい
課題は
- API応答に時間がかかる
- GASの6分制限がボトルネック
アーキテクチャ構成

GASは完全に排除するのではなく、必要に応じて手動トリガー用として残せる設計にしています。
ポイントは:
- 毎日実行はCloud Scheduler
- 重い処理はCloud Run
- スプレッドシート更新もCloud Run側で完結
これにより、GASの実行制限から完全に解放されました。
IAMサービスアカウントの設計
Cloud Runからスプレッドシートを更新するために、専用のサービスアカウントを発行しました。
手順概要
- IAM & 管理 → サービスアカウント作成

- 以下のロールを付与
- Cloud Run Invoker(必要に応じて)
- Logs Writer
- Editor(またはSheets API限定ロール)
- Sheets APIを有効化


- 対象スプレッドシートにサービスアカウントのメールアドレスを共有

Cloud Run Functionsのコンテナ設定
今回はCloud Run Functions(第2世代)を使用しました。

主な設定
- ランタイム:Node.js 20
- メモリ:512MB
- タイムアウト:最大60分(実際は10分程度)
- 同時実行数:デフォルト
API呼び出しは並列化しています。
またコード内で使用するため、自動化したいスプシのIDをSPREADSHEET_IDとして環境変数に登録しておきます。

ディレクトリ設定
Cloud Run Functions側のコードは、できるだけ責務を分離したシンプルな構成にしています。
/src
├ index.js // エントリポイント
├ gasShim.js // GAS互換レイヤー
└ main.js // スプレッドシート更新処理エントリポイント:index.js
Cloud Run FunctionsではHTTPハンドラを定義します。
今回はCloud Schedulerから呼び出すだけなので、非常にシンプルです。
import { runBatch } from "./batch.js";
export const main = async (req, res) => {
try {
await runBatch();
res.status(200).send("success");
} catch (err) {
console.error(err);
res.status(500).send("error");
}
};GASコード資産を活かす:gasShim.js
今回の工夫ポイントはここです。
既存のGASコードをなるべくそのまま使いたかったため、gasShim.jsを作成しました。
GAS特有のオブジェクト(例:UrlFetchApp, PropertiesServiceなど)をNode.js環境で疑似的に再現するラッパーです。
例えば、GASでは次のようにスプレッドシートを操作します。
const sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();このAPIをNode.jsでも使えるように、SpreadsheetAppをラップしたクラスを用意します。
const { google } = require('googleapis');
class SpreadsheetAppShim {
constructor(spreadsheetId, auth) {
this.spreadsheetId = spreadsheetId;
this.sheetsApi = google.sheets({ version: 'v4', auth });
}
getActiveSpreadsheet() {
return this;
}
async getSheets() {
const res = await this.sheetsApi.spreadsheets.get({
spreadsheetId: this.spreadsheetId
});
return res.data.sheets.map(
s => new SheetShim(this.spreadsheetId, s.properties.title, this.sheetsApi)
);
}
}内部ではGoogle Sheets APIを呼び出していますが、外側から見るとGASのAPIとほぼ同じインターフェースになります。
これにより、
- GASで書いた既存コードをほぼそのまま移植可能
- Cloud Run上で実行可能
- ローカル開発もしやすい
というメリットがあります。
この設定をした場合、GASでこのように書く場合
const values = sheet.getRange(1,1,10,3).getValues();Cloud Run Functionsのmain.jsでは以下のように再現できます。
const values = await sheet.getRange(1,1,10,3).getValues();
スプレッドシート更新:main.js
これまで使用していたGASのコードを、上記のgasShim.jsに合わせて少し修正します。

Cloud Schedulerで定期実行設定
GASでトリガーを作成するように、Cloud SchedulerでCloud Run Functionsのエンドポイントを定期実行します。
Cloud Schedulerでジョブの作成から名前/cronでの頻度設定を記載します。
実行内容の構成の部分では「HTTP」、URLにはCloud Run Functionsで作成したURLを記載します。

これにより、GASのトリガーを使わずに安定した定期バッチ処理を実行できます。
まとめ
今回、GASで動かしていたスプレッドシート更新処理をCloud Runへ移行することで、実行時間制限の問題を解消しました。
GASは手軽に自動化を作れる反面、実行時間が最大6分という制限があり、API連携など時間のかかる処理ではどうしても不安定になりがちです。
そこで重い処理はCloud Run側に移し、Cloud Schedulerから定期実行する構成にしました。
また、既存のGASコードをできるだけそのまま使うために gasShim.js を用意し、GASのAPIに近い形でスプレッドシート操作ができるようにしています。これにより、ロジックを大きく書き換えることなく移行できました。
GASの6分の壁に悩んでいた方もぜひこの方法をご活用ください!










