この記事は17256 回閲覧されました。

Google Apps Scriptの中で地味ながら、その活用の幅が実に広いものとして、スクリプトトリガーがあります。いわゆる時限式で作動させるための仕組みなのですが、スクリプトトリガーは、スクリプトエディタの画面から入り、手動で登録するのが通常のフローです。しかし、「スクリプト内でテンポラリで時間トリガーを設置したい」であったり「トリガーの設置し直し」など、スクリプトエディタにいちいち入らず設定したいシーンがボチボチあります。そういった場合には、スクリプトからトリガーの設置や削除が出来ると便利です。二重に登録してしまったりすると、二回発動したり、片方しか発動しなかったりするので、慎重に設置をしましょう。

これらトリガーは大きく分けて4種類あり、1.時限作動式 2.開いた時 3.編集時 4.フォーム送信時を設置することが可能です。主に使うのは時限作動式と、フォーム送信時の2つになります。但し、このスクリプトトリガーはちょっと癖があるので、そこだけは注意しとかなければなりません。

目次

使用するクラス、メソッド

トリガーの設置

スプレッドシート編

スプレッドシートでは、時間ベーストリガーの他にも、スプレッドシート特有のトリガーを設置する事が出来ます。使用することの出来る特有のトリガーは、「onChange」、「onEdit」、「onFormSubmit」、「onOpen」の合計4つとなります。それぞれ、「変更時」「編集時」「フォーム送信時」「起動時」の4つに該当します。以下に各トリガー設置のスクリプトを記載します。

onChange(変更時)

変更時とは、構造変更や内容変更が発生した時に発動するトリガーです。VBAで言う所のAfterUpdateイベントと言えます。

onEdit(編集時)

編集時とは、編集時に毎回発動するトリガーです。VBAで言う所のBeforeUpdateイベントと言えます

onFormSubmit(フォーム送信時)

フォーム送信時とは、スプレッドシート側から作成したフォーム上でデータが送信された時に発動するトリガーです。

onOpen(起動時)

起動時とは、そのスプレッドシートが開かれた時に発動するトリガーである。通常はメニューの登録などでよく使われている。

フォーム編

フォームでは、時間ベーストリガーは使用することが出来ません。また、使用できるトリガーはリファレンス上では、「onFormSubmit」、「onOpen」しかありません(しかし、実際にトリガー設置画面だと、onEditがあったりします)。殆ど、スプレッドシートと同じですので、ここでは省略します。変更箇所は、.forSpreadsheetが .forFormになるだけです。

時限作動式編

スクリプトトリガーで最も使用する機会が多く、また、設置できるパターンの多いトリガーです。結構細かく時間トリガーを設置することが出来ますが、あまりにも短い時間にバンバンデータを取り込むようなトリガーを設置してしまうと、GoogleのサーバーにBANを食らったり、正常に動作しなくなることも考えられるので、設置に当たっては気をつけましょう。また、このトリガーが設置されたものは、例えファイルがゴミ箱に行こうともトリガーは動き続けますので、捨てる場合には、トリガーを削除してから捨てるようにしましょう。

ここでこのトリガー使用上の注意点です。

  1. これらのトリガーは、すべて±15分のラグを持って作動するようなので、分単位での綿密なトリガー作動は期待してはいけません。
  2. 時間ベーストリガーの場合、SpreadsheetAppなどを使う時にはOpenByIdを利用するようにしましょう。getActiveSpreadsheetではエラーになる事があります。
  3. 同様の理由でgetuiなども無意味ですのでメッセージボックス関係などのコードは外しておきましょう。

ミリセカンド後に実行

単位がミリセカンド(1/1000秒)なので、通常は数秒後という形で設定して使う時間トリガーです。下記の例では10秒後に実行するよう設定しています。

特定日に実行

単位が特定日のスポット実行なので、日付型でデータを受け取っておき、atに続けて引数で渡してあげます。

特定日に実行(深夜に実行)

特定日に実行のものと殆ど同じですが、こちらは、深夜付近で実行がされるトリガーです。atDateに続けて引数で渡してあげます。

○○時に実行

引数で取った数字(時間)に従って、その時になったら発動するトリガー。このトリガーは、この後に出てくる別のトリガーと組み合わせて使用します。下記ではeverydaysと組み合わせて使用しています。サンプルの例の場合、3日置きに午前5時〜6時の間でトリガーが発動します。

毎日○○時間毎に実行

引数で取った数字(時間)に従って、毎日その時間にトリガーが発動します。下記の例では、毎日12時にスクリプトが実行されます。

毎分○○ごとに実行

引数で取った数字(分)に従って、○○分毎にトリガーが発動しつづけます。指定できる引数は、1分・5分・10分・15分・30分が指定可能です。

指定週毎に指定曜日の指定時刻に実行

everyWeeksで毎週なのですが、引数に指定した数字にて、2週毎といった指定ができます。また、この指定オプションは、必ず、指定時刻とどの曜日なのか?を指定するatHourとonWeekDayの指定が必要です。

タイムゾーンの指定

Googleドキュメント全般には、それぞれプロパティを見るとわかるのですが、アメリカ合衆国になっていたりすることがあります。スクリプトでもそれがあり、場合によっては、変更しておかないと妙な挙動をするスクリプトを作る羽目になります。このオプションは、そのタイムゾーンを指定することの出来るメソッドです。

トリガーの修正と削除

トリガーの修正・削除は、いずれもまずは削除から始まります。そして、修正だけはこの後に改めて設置をするメソッドを発行することになります。しかし、スクリプトトリガーは設置者以外のトリガーが見えなかったりするので、Google Styleで紹介されているトリガー削除ルーチンがとても便利です。このルーチンの後に設置などのルーチンをつなげてあげれば、トリガーの設置し直しが完了するわけです。

しかし、このルーチンは、triggerIdが引数で必要であるため、自分の場合、引数をなくして、以下のようにし「トリガー全削除ルーチン」に改造して使います。

但し、当たり前ですが、トリガー全削除ルーチンは、根こそぎ全部削除してしまいますので、キメ細かくトリガーセッティングをしているケースでは、何か別の仕組みが必要になってくると思います。自分の場合、別にトリガーをワンボタンで設置する為のルーチンを用意しておいてあります。

もっと柔軟にトリガーを設置してみる

一見すると便利そうなスクリプトトリガーという機能ですが、実はめちゃめちゃ融通が効きません。細く設定できそうなトリガーの条件設定なのですが、モノすごくアバウトにしか設定できません。いい事例が、毎日10:30に発動とか、そういったことが出来ません。30分っていう設定は、分トリガーにしかなく、他は時間トリガーしかないわけです。そうなると、時間トリガーしかなく、割りと大きな情報収集トリガーを2本発動させた後にPDF化して送信というスクリプトを書くとなると、3時間後とかになってしまいます。そこで、これを何とかしようというのが今回の目的。

※尚、2本の情報収集トリガーは同時に発動すると、データが壊れるので時間を空けて挙げなければならない。

解決したい課題(自分の事例)

  • データは洗い替えで収集するので、毎回データ取得前には、データをクリアする必要性がある。(clearsheet関数を作成)
  • 取得したデータに対してFilterでフィルタしたものをPDFにしているので、日付データを毎日設定し直す。(filterday関数を作成
  • 日付と時刻指定トリガーを3つ設置する(本日の10:00, 本日の10:30, 本日の11:00)
作成するコードとトリガー
  • 全トリガー削除関数を作成する
  • データのクリア、日付の変更、全トリガーの削除、全トリガーの設置し直し(settingAllTrigger関数)という一連の作業を行うルーチン(specialdays関数とする)を作成する。このルーチンをトリガーとして、毎日AM1:00に発動するように設置する。この関数の中に、settingAllTrigger関数が最後に呼び出されるように含まれている)。
  • 上記ルーチンを実行するトリガー(settingAllTrigger関数とする)を作成する
  • ややこしいですが、settingAllTrigger関数もまた、全トリガー削除のルーチンの対象になります。
  • 但し、onOpen関数は毎回設置されていないとちょっと困る事情があるので、settingAllTrigger関数に含めて置きます。
  • 特定の日時でのトリガー設置の為に日付を構築する関数を用意してあげる(getDate()とする)。
で、結果的には・・・
毎日、AM1時にspecialdays関数が発動して全トリガーとデータの消去が行われた後、settingAllTrigger関数が呼ばれて新たに、以下のトリガーが設置されます
  1. onOpenのトリガー
  2. specialdays関数のトリガー(毎日AM1:00で設定)
  3. 本日の日付と特定時刻で設定されているAM10:00発動のデータ収集トリガー1本目
  4. 本日の日付と特定時刻で設定されているAM10:30発動のデータ収集トリガー2本目
  5. 本日の日付と特定時刻で設定されているAM11:00発動のPDF化&メール送信トリガー
の5本が、毎日設置され直されて継続していくわけです。こうすることで、非常に柔軟性のあるトリガーを設置して細かく挙動をコントロールすることが可能になります。

ソースコード

  1. このスクリプト群は、一度そのスプレッドシートのIDをスクリプトプロパティに格納しておく必要があるので、最初の1回だけsetup()を実行する必要性があります。
  2. 当たり前ですが、最初の1回だけは、手動でトリガー群を設置しないといけないので、settingAllTrigger()を実行する必要性があります。以降は、トリガーが勝手にやってくれるので、必要ありません。
  3. 特定の日付のトリガー用に、trigger1~3の変数を用意して、getDate()関数で整形して上げた値を返してあげています。

特定の日時のトリガーを作る上でのポイント

毎度毎度のことなのですが、Googleのリファレンスに載っていないので、色々情報を集めて、特定の日付・時刻によるトリガーの設置の為に、getDate関数を作成しました。引数に時間(HH:MM形式)を受けて、返り値として(YYYY/MM/DD HH:MM)の形で返すようにしています。getDate(“10:30”)とやると、返り値として本日の日付の10:30の日付型で値が返ってくるので、これをスクリプトトリガーのatに渡してあげるわけです。整形は、Utilities.formatDateで行っています。当たりまえですが、更にこれをnew Dateで日付型に戻して挙げるわけです。

下記は、今日の日付の10:40の日付型の値をtrigger1変数に受け取るコードです。時刻部分を、ユーザに入れさせるように、何かギミックを用意するのも悪くありませんね。

下記は、受け取ったtrigger1の値をもとに、Script Triggerのat()をつかって、特定の日付・時刻を指定しています。

直接、at()の中に、【YYYY-MM-DD HH:MM】で書けたら楽なのにね・・・

ポイント

トリガー対象となっているスクリプト内では、自動的にそれらが動くわけなのですが、通常とはちょっとだけ異なる挙動になるのと、タイムアウトの5分を意識して作らなければなりません。もし、スクリプトの実行が失敗しますと、サーバーからメールが飛んできます。

  • スクリプトトリガー作動時のユーザは設置者の権限となります。故に、メールアドレスなども設置者のメアドがログに残ることになります。
  • 複数の人間が同じトリガーを設置してはなりません。また、他の人からは他の人間が設置したスクリプトトリガーは見えませんので要注意です。タブってトリガーが発動されることになります。
  • 値を他のシートからかき集めて、集計するタイプのものは、タイムアウトに注意!
  • 集計したさらに先に、PDFを作成して格納するようなルーチンを書く場合には、スクリプトトリガーの発動時間を当たり前ですが、ずらしておく必要性がある。でないと、集計されきってないのに、空のPDFが作成されたりする。
  • 複雑な関数を自分で作成し、スプレッドシート内で関数として使っている場合、「読込中・・・」のままになり、これをPDF化するような自動化を行うと、全く帳票として使い物にならないものが生成されるので、なるべくなるべく、スプレッドシート上で使用する関数は標準の関数を使用すること(自作関数はどうしてもスピードでは圧倒的に負ける)。
  • 時間トリガーはあくまでも指定した時間~時間のどこかで実行されるものなので、確実に何時何分という指定はできない。
  • 通常は、getActiveSpreadsheetなどで取得しているシートは、openByIdにしておくこと。もちろん、自分自身のIDを取得するような関数も用意しておいて、予めスクリプトプロパティに格納し、呼び出す仕組みが望ましい。でないと、書き込みなどが出来ずに終わってしまう。

関連リンク

Pocket
このエントリーをはてなブックマークに追加
Bookmark this on Yahoo Bookmark
Pocket