Google Apps Scriptの制限事項や注意点をまとめました【GAS】
せっかくの春ですので、今年度からGoogle Apps Scriptを初めてみようか?と思っている人向け・・・とは言えないかもしれませんが、GASを扱っていてぶつかる可能性のある各種制限事項や注意点についてまとめてみました。
結構制限事項があり、踏み込んで使おうとすればするほど不可解なトラブルが待っていたりします。特にコードは正しいはずなのに動かないというケースはこの制限事項などに引っかかってる恐れがあるので、一度確認してみてください。
GASの制限事項
Quota関係
実行時間の制限
Google Apps Scriptは現在全プランに於いて連続稼働時間は6分までという制限が存在しています。そのため、効率の悪いコードを回したり、膨大な数のスプレッドシートのデータを拾ってくるなどしてると、6分の壁にぶつかり処理が途中で中断してしまいます。
そのため、なるべくAPIを叩く回数を減らすための努力や、高速化を図るための努力をする必要性があります。処理できる時間に大きな差が生まれる為、なるべく早い段階からこれらをカバーするテクニックを身に着けておかないと、おいおい苦しめられることになります。
以下のエントリーでは高速化をするテクニックおよびどうしても6分を超える場合の壁を超えて実行するテクニックについてまとめています。
サービスとしての利用上限
Google Apps Scriptには明確にサービス単位でQuotaと呼ばれるものが設けられています。アカウント単位や1日単位、単位秒数当たり、などなど様々な閾値が設けられているため、実行する場合には意識して超えないようにしなければなりません。以下はGoogle Workspaceの場合です。
この中で主によく遭遇するものをピックアップしてみました。
- 同一スクリプト同時実行数の上限:30ユーザまで。ウェブアプリに同時に30名以上アクセスすると起こりやすい
- メール送信上限値:2000通/1日/1アカウントまで。DMなどで大量に送りたい場合には、GCP上にSendGridを構築したり外部のサービスを利用したほうがベター。
- トリガーによる実行時間上限値:6時間/1日/1アカウントまで。何個も複数のスクリプトで配置してると超えがちです。
- スプレッドシートの作成上限値:3200個/1日/1アカウントまで。ドキュメント生成よりは制限値がゆるいけれど、一番多く使うので注意。
- ユーザ定義関数の連続実行上限値:30秒まで。超えるとスプレッドシート上でソレ以降のセルはエラー表記となる
- メールの添付ファイルサイズ上限値:25MBまで。社内宛てはドライブへのリンクとして、社外に送る場合はなるべくコンパクトにしましょう(特に画像の縦横のサイズが無駄に巨大なのとか)
- UrlfetchAppで扱うファイルサイズ上限値:50MBまで。ファイルのダウンロードやアップロードで超えやすい。Drive APIで回避する方法がある
- ウェブアプリのデプロイ履歴上限値:最大200個まで。上限値に達するとデプロイできなくなるので過去のを削除する必要がある。
- スプレッドシートのセルの上限値:1000万セルまで。データを集約時に超える可能性は十分ある。
他にもDriveへのファイルアップは1日1アカウント750GBまでといった制約があるけれど、GASで達することはほぼあり得ないので気にしなくて良い。
また、ウェブアプリの場合「デプロイした人の権限で動かす」とした場合、その人がAPIを叩いてることになるので制限値に引っかかりやすくなります。アクセスしてきてるユーザの権限で動かすようにすれば分散できるので回避しやすくなります。
リクエスト間隔の上限
Google公式ドキュメントには記載が無いのですが、外部サービスのREST APIを叩く際に利用するUrlfetchApp、このメソッドには2つの側面で制約があります。
- 短時間に何度もUrlfetchAppを叩くと429エラー(Too Many Request)が発生してスクリプトが止まります。
- また、相手側サーバでも指定時間内に既定値を超えるリクエストを投げると同様に429エラーを返されてエラーとなります。
前者の場合はGoogleのサーバから返されるもので、1秒間に4回以上のリクエストを投げると起きるのを確認しています。よって、3回なげたら1秒間ウェイトを入れるためにUtilities.sleep(1000)を入れて調整してあげる必要があります。
また、Google側はよくても、相手側のREST APIのサーバ側にも当然制限があり、1分間に何回までとリクエスト上限があるのが通常です。これを超えないように同様にウェイトを入れてスピード調整して上げる必要があります。
しかし、ウェイトを入れるということはそれだけ処理の合計時間は伸びることになるので、前述の実行時間の制限に引っかかる可能性があるので要注意です。
言語仕様による制限
Google Apps ScriptはほぼJavaScriptなのですが、規格的にはEcmaScript2019までの対応となっています。また、サーバサイドで動く言語ですのでそれにまつわる制限もあります。
- ローカル環境のファイルにアクセスは出来ません(必ずドライブやウェブ上に配置してある必要があります)
- sleepメソッドやwindowオブジェクトを扱えません(GASにUtilities.sleepがあるのでそれに置き換える)
- exportやmoduleといった仕様に対応していません。
- グローバル変数はファイルが別でも重複させることが出来ません(常に1プロジェクトでユニークである必要があります)
- ウェブアプリはiframeのsandbox内で実行されてるため、時々挙動がおかしい事例がある
- ウェブアプリはSPAな仕様のものしか作れないため、画面遷移は出来ない(画面遷移っぽい作り方をする必要がある)
- ウェブアプリへのアクセス制限は自分のみか?組織全体か?の基本2択(特定ユーザのみ使わせる場合は別途ロジックが必要)
- JavaScript用のライブラリがそのまま使えるとは限らない(PDFLibはちょっと手修正を加えたら動きました)
- UrlfetchAppではUser-Agentの書き換えが出来ないため、特定のREST APIへのアクセスが送れない場合がある。
- UrlfetchAppでスクレイピングをする場合は、JSで書き換えをしない静的なページしか操作できない(動的なページはCloud FunctionsでPuppeteerを動かす必要がある)
- 通常GASは上から下に向かって同期的に実行されるが、google.script.runで呼び出す場合は非同期で実行され次の処理をまたずに進んでしまう(コールバックなどを使って順次処理を実装する必要がある)
- ウェブアプリ側からはGASのライブラリ内にある関数を直接実行することが出来ない(間に橋渡しする関数が必要)
- GASでクラスなどを構築した場合、親クラスがいるファイルが呼び出す側より下の順番にある場合、エラーにある(必ず呼び出される側よりも上にファイルがいなければならない)
- GCP側のサービスアカウントはGoogle Apps Scriptのコードを実行することが出来ません。
似てるけれど違うメソッド
Google Apps ScriptにはGoogle Workspaceの様々なサービスをAPIという形で呼び出して数々のメソッドが簡単に使えるようになっています。しかし、このメソッドなのですが、似たようなものが違うクラスにも用意されていたりします。そして、そちらは管理者権限が必要であったり出来ることに大きな差があったりします。
主な例示をあげると
- MailAppとGmailApp:どちらもメールを送れる。けれど後者のほうが高機能で出来ることが多い。
- GroupAppとAdminDirectory:どちらもグループを扱える。けれど後者のほうが高機能で管理者権限が必要。
また、既に一方は廃止されてしまいましたが並行運用されたのちに統合されたものがあったりします。
- DocsListとDriveApp(Drive API):どちらもドライブを扱える。けれど後者のほうが高機能だけれど一部掛けてる機能がある。
- ContactsAppとPeople API:どちらも連絡先を扱える。後者のほうが高機能だけれど扱いが難しい。
他、Advanced Google Serviceで扱えるSheet APIはスプレッドシートを扱えますが、SpreadsheetAppと違ってまとめてバッチ処理などGASのメソッドにはない利点があったりと、GAS側のメソッドのほうが全部を網羅していないことが多々ありますので、使い分けが必要です。
スコープが足りない場合
GASはスクリプト初回実行時に必要な権限について承認をもとめてきます。基本は承認すればそれでオッケーなのですが、一部のAPIを実行する場合これでは足りないケースがあります。
- Advanced Google ServiceでAPIを有効にした場合に一部のAPIでoAuthScopeに明示的にスコープを記述しないと動かないケースがある(Google Chat APIなど)
- Picker APIなどHTML側で使うライブラリを動かす際にダミーでDriveAppを承認するようにコードをいれておかないとファイル選択ができない。
- おなじくBigQuery APIを使う場合、スプレッドシートを外部テーブルとしてリンクしてるものを操作する場合、ダミーでDriveAppを承認するようにコードをいれておかないとエラーになる。
- 一部のAPIはGASのプロジェクトをGCP側プロジェクトと連結して、GCP側でもAPIを有効化する必要性がある
- GCP側のAPIなのだけれど、1.同様にoAuthScopesで明示的にスコープを記述しないと叩けず403エラーになるケースがある(Geminiを叩く事例がそれでした)
- 一部の特殊なAPIを実行する場合は、Google Apps Script APIをオンにしないと実行することが出来ません(ソースコードやappsscript.jsonをGASから書き換えるようなケース)
トリガーで呼び出す時の制限
スクリプトトリガーで自動実行をする場合に呼び出し時に於ける制限があります。
- onEditなどのシンプルトリガーの場合、SpreadsheetAppのようなスコープを要求するコードを使用することは出来ません。
- 時間トリガーに於いて、関数に引数を指定することは出来ません(スクリプトプロパティなどを併用して実行される関数側で制御が必要)
- 時間トリガーの場合、getActiveSpreadsheetなどが正しく動かない。openByIdなどで明示的にファイルを指定する必要がある(実行時にファイルが開かれていない為)。
管理コンソールから制限
2024年、いつの間にか管理コンソールに於いて「Google Apps Script」のオンオフの項目がドライブとドキュメントの項目に追加されていました。これまでのGoogle Apps Scriptは誰でもコードを書けて実行できる状態で、管理コンソールから特定のユーザには開発させないであったり、実行させないといったことが出来ませんでした。
そこで、特定の組織部門に対してこの機能をオフにした場合、どのような挙動になるのか?検証してみました。テスト用にCloud Identity Freeのアカウントをこの組織部門に所属させて、GASが実行できるかどうか?テストをしています。
- スプレッドシートを開いて、スクリプトエディタを開くと400エラーとなり開けなくなります。
- 当然メニューなどをonOpenで開こうとしても開かれることはありませんし、実行出来ません。
- ウェブアプリを構築し、次のユーザとして実行で「ウェブアプリケーションにアクセスしてきてるユーザ」にしてデプロイしたものにアクセスすると、「ウェブアプリへのアクセス権がありません」と出て実行出来ません。
- 逆に次のユーザとして実行で、制限の掛かっていないユーザでデプロイしたものにアクセスすると、ウェブアプリにアクセスすることは可能です。
- GASの作成はやらせたくないけれど、実行はさせたいといった事は出来ないので、オフにすると開発も実行も出来なくなります。
もう少し細かく制御できたらよいのですが、これまでのようなむやみやたらに開発可能で実行可能といった状態から、管理者が制御出来るようになったので、野良アプリの量産に一定の制限が出来ますし、ウェブアプリであれば制限の掛かっていないユーザのアプリにはアクセス可能なので、こちらを使うことは可能なので、一歩前進といった所です。
図:スクリプトエディタは開けなくなる
図:ユーザ権限でのウェブアプリは開けない
図:管理コンソールでの設定箇所
運用上の注意点
サーバー障害で実行されない
GASはGoogleのサーバ上で実行されているため、サーバ障害や大規模アップデートがあった場合に特定のメソッドが動かないということがままあります。ステータスダッシュボードを見ても障害は記録されないので役には立ちません。
通常は翌日には直ってることが多いのですが、アップデートによる障害などはIssue Trackerに報告が上がってることがあります。しかし、中にはこのアップデートは仕様であり正常であるということでIssueの修正を拒否されてしまってるケースもあります。
その場合StackOverflowなどで解決策が提示されてることがあるので、それらを確認して回避策を講じる必要性があります。
複数アカウントでログインしてる場合
結構報告があるトラブルなのですが、スプレッドシートを開いてスクリプトを実行したら意味不明なエラーで実行されないであったり、ウェブアプリケーションにアクセスしたら動かないというケースがあります。
このトラブルはGAS側の問題ではなく、利用者がChromeに複数のアカウントでログインしてる状態で、ユーザ切り替えがうまくいかずに発生している現象です。どうもGASはCookieのログイン制御がうまく動かないようですので以下の解決策を実行します。
- 1つのプロファイルで複数ログインせず、1アカウント1プロファイルでユーザ切り替えをしてもらうようにする
- 一旦全部のアカウントをログアウトして、GASで利用するアカウントのみでログインして利用してもらう
トリガーにまつわるトラブル
スクリプトトリガーは業務自動化にとって大変便利で優れた機能なのですが、ちょっと困った問題があります。
- トリガーは設置した本人しか見えないし、削除できない(後述の引き継ぎ問題にもつながる)
- GUIでセットするトリガーは時間帯指定になるので正確な時刻に発火させることが出来ない
後者はトリガー設置自体をスクリプトで行わせることで正確な時刻に発火させることが可能といえば可能ですが、必ずしもズレなく実行されることを保証していないので、そこは留意する必要があります。
また、GASのタイムゾーンがニューヨークになっていて実行時刻がズレてるというケースがあります。開発画面からタイムゾーンがきちんと東京になってるかどうかを確認しましょう。
作り込み過ぎに注意
GASはExcel VBAのようなポジションでありながら、ウェブアプリまで作成できたり、トリガーで自動実行まで出来る為、単一の目的であるならば外部サービスにお金を出すよりも自前で用意してしまったほうがコスト面で圧倒的に優れてるケースがあります。
しかし、複数名での共同開発にあまり向いていない点や、開発画面があのようなスタイルなので全体の見通しが良くない、個人開発なので下手すると仕様書もなにも無いということがあるので、あまりアレもコレもと機能を増やして増強していってしまうと引き継ぎが発生する場合に困難が待ち受けてるケースがあります。(これはVBAでも起こり得ること)
Togetterにもこれに関するような事例が掲示されていたりします。属人化しやすいので止まって困るようなシステムは情シスが積極的に巻き取って管理をしてあげる必要性があります。
- 「Excelできる人が辞めてしまったので手作業で」→「Excelできる人が入社し自動化」→「否定されてExcelできる人退職〜無限ループ」の地獄の流れ「まさにうちもこれ」
- 顧客「長年1人で社内システムを開発していた社員が退職し、新規のシステムに刷新したいので見積りを。予算は5千万」→その結果こうなった
- 退職した社員のExcelの解析相談され見積もりを出したら「高い。他を当たる」となった企業が出戻ってきた話
外部公開時に予期しない関数を実行される可能性
Google Apps Scriptのウェブアプリケーションではgoogle.script.runでGAS側の関数を呼び出して実行することが可能です。しかしこれが原因でセンシティブな情報が漏洩する可能性があります。
- ウェブアプリのみ公開でスプレッドシートは誰とも共有していない
- スクリプトプロパティなどにAccess Tokenやセンシティブな情報を格納して外部APIなどをリクエストしてたりする
- その値を取り出すための関数が用意されている(ここがポイントです)
- もし利用者がこの関数の存在をしってる場合、Chromeのデベロッパーツールでウェブアプリを直接書き換えて実行し、取り出せてしまう可能性がある
対策は取り出すための関数やWeb側からは実行されたくない関数は「プライベート関数(関数の先頭にアンダーバーをつけた関数)」にしておく必要性があります。この場合GASの内部からは実行でき、Web側からは呼び出せなくなります。
実行時のアクセス権限について
結構やりがちなのですが、開発してる自分はバッチリコードが動くのに、第三者に渡して実行してもらったら動かないといったケースがありますこの理由は殆どがアクセス権限によるものです。
- ファイル操作に於いて自分はファイルへのアクセス権限があるので動くが、渡した相手はアクセス権限が与えられていない
- 自身はGoogle Workspaceの特権管理者なので管理用APIを実行することが出来るが、渡した相手は管理ロールがないので実行できない(Admin SDKなどが代表例)
- 自身のGCP環境とアクセス権限は持っているが、相手はその環境へのアクセス権限がないのでAPIを実行できない
自分では気が付きにくく、嵌まるポイントになっています。
一方でウェブアプリの場合自分自身の権限で動かす場合、特権管理者のAPIであっても自分がその権限を持っていれば動かすことが可能です(代理で実行してるだけなので)。故にウェブアプリの場合にはアクセス権限をどうするのか?をよく考えてデプロイする必要があります。
ソースコードの外部保守
GASはあの開発画面で通常は開発することになるため、ソースコードとかのバックアップや第三者と共有したい場合どうする?といった問題があります。しかし、以下の手法でコードのバックアップや保守管理を行うことが可能です。但し、Google Apps Script APIをオンにしておく必要があります。
- claspを利用してローカルで開発して、GAS側へpush / pullすることが可能(但し開発言語がTypeScriptになっちゃう)
- Google Apps Script Github Assistantを導入することであの開発画面からGithubに対してpush / pullなどが操作できるようになる
いずれも、開発するのに開発環境を別途用意したり、GithubやNode.jsに関する知識を要求するなどハードルが一気にあがるため、個人的には普段の開発ではオススメしづらい。
個人アカウントで運用しない
GASの開発に於いてとっても重要な要素なのだけれど見過ごされがちなのが「個人のアカウントで開発して社内で運用してる」というケース。じつはこれ結構なリスクがあり、主に担当者が異動や退職でアカウントが消された場合に発生します。
- 個人のマイドライブ内で開発され共有されてる場合、アカウント削除とともにファイルごと消えます(共有ドライブに配置することで回避出来る)
- トリガーなどを設置してる場合、設置者本人しか見えない/削除できないので、延々と動き続ける。またアカウントを削除すると停止してしまう。
- ウェブアプリをデプロイしてる場合、アカウントを削除されるとウェブアプリが消える。
- 内部異動で対象のファイルに元担当者がアクセスできなくなり、引き継ぎ者のアカウントでウェブアプリを再デプロイする必要性がある。
故にこれらを回避する為には、社内で広く利用するようなアプリの場合には、特権管理者のアカウント内で管理するか?専用のアカウントを用意してそちらでデプロイや管理をするようにする必要があります。トリガー設置もウェブアプリのデプロイも専用アカウントであれば退職や異動で消えることもなく、引き継ぎ者はそのアカウントで入れば作業が継続できるので安心です。