[ノンプロ研]GAS中級講座6期Day4 Utility services1

GAS

どうも。つじけ(tsujikenzo)です。このシリーズでは、2021年9月から始まりました「ノンプロ研GAS中級講座6期」について、全7回でお届けします。今日はDay4です。

前回のおさらい

前回は、「組み込みオブジェクト」 をお届けしました。

今回は、 「Utilitiy services1」 をお届けします。

今日のアジェンダ

  1. Utilitiy Servicesになりました
  2. Script Serviceとトップレベルオブジェクト
  3. トリガーから作成できないトリガー

GAS中級講座5期の補講ブログでは、以下をお届けしています。

  • トリガーの正式名称
  • シンプルトリガーの4つのポイント
  • シンプルトリガーは認証不要でAPIを呼び出せる
  • 与えた認証の削除
  • シンプルトリガーはバインドしているファイル以外にアクセスできない
  • インストーラブルトリガーの設置アカウントと発火
  • トリガーは編集権限を失うと削除される
  • イベントオブジェクトの公式リファレンス
  • getUi()とaddMenu()メソッド
  • Properteiesサービスのデータ量
  • UserPropertyの使いどころ

前回の補講ブログは、どちらかというと、スクリプトエディタとトリガーメニューを使ってトリガーを設置する内容でした。

読んでいただければ、講座がさらに理解できる内容になっていると思います。

今回の補講ブログでは、トリガーはオブジェクトであるという視点から、理解を深めたいと思います。

Utility Servicesになりました

2021年10月に、Google Apps Script内で、アップデートが行われ、Script Serviciesの名称が、Utility Servicesになりました

Reference overview  |  Apps Script  |  Google for Developers

Google Apps Scriptは、以下の3つのServicesと1つのResourcesからなります。

  1. Google Workspace services
  2. Other Google services
  3. Utility services
  4. Script project resources 

Utility Servicesは、以下の4項目で構成されています。

  1. API & database connections
  2. Data usability & optimization
  3. HTML & content
  4. Script execution & information 

とくに、中級講座後半であつかうServiceは、以下の5つです。

  • URL Fetch
  • Utilities
  • Base
  • Properties
  • Script

どのServicesに所属(分類)するのかは、覚える必要はありません。

なんとなく、これらのServiceはUtility Servicesにあったなぁと思っていただければ十分です。 

Script Serviceとトップレベルオブジェクト

Script Serviceは、その名のとおりスクリプトを操作するサービスですが、以下のような項目を取り扱います。

  • トリガーの操作
  • スクリプトの公開
  • イベントに関するプロパティ

今回はトリガーの操作について、お届けします。

さっそく、トップレベルオブジェクトのClass ScriptAppを見てみましょう。

トリガーを扱うさまざまなプロパティやメンバーが登録されています。

**newTrigger()deleteTrigger()**などは、これから何度も呼び出すメソッドです。

これらは、ScriptApp(トップレベルオブジェクト)のメソッドであることを理解しましょう。 

newTrigger()メソッドとTriggerBuilderオブジェクト

newTrigger()メソッドの戻り値は、TriggerBuilderオブジェクトです。 

TriggerBuilderオブジェクトとは、なんでしょうか。クラスを確認しましょう。

クラスを確認すると、5種類のTriggerBuilderオブジェクトがあるようです。

  • ドキュメントを開いたときに発火するトリガーを作る
  • フォームを開いたり送信したときに発火するトリガーを作る
  • スプレッドシートを開いたり編集したりしたときに発火するトリガーを作る
  • カレンダーのイベントを更新しときに発火するトリガーを作る
  • 時限式トリガーを操作する 

つまり、Script Serviceでは、このような流れでトリガーを作成します。

  1. トップレベルオブジェクトからTriggerBuilderオブジェクトを作成する
  2. TriggerBuilderオブジェクトから DocumentTriggerBuilderや、SpreadsheetTriggerBuilderなどのサービス名+TriggerBuilderオブジェクトを設定する
  3. サービス名+TriggerBuilderオブジェクトのcreate()メソッドで、Triggerオブジェクトを作成する

最終的にTriggerオブジェクトは、実行されたり参照されたり設置されたり削除されたりします。

「時間置きに」とか「スプレッドシートが開いたら」などは、あくまでサービス名+TriggerBuilderオブジェクトのcreate()メソッドでTriggerオブジェクトが生成された結果です。

Class SpreadsheetTriggerBuilderから生成されたTriggerオブジェクトを、Class DocumentTriggerBuilderから生成されたTriggerオブジェクトに変更したり、時限式トリガーを設定することはできません。

Class Trigger

Class Triggerを見てみましょう。

get系のメソッド しかありません。

なので、いちど作成されたTriggerオブジェクトに対して、発火時刻を再設定したりできません。 

さらに、Triggerオブジェクトは、設置したらプロジェクト内にずっと残ります。

使い終わったTriggerは削除します。その感覚になれていきましょう。

トリガーの作成は変数に格納しない

公式リファレンスにもあるとおり、トリガーは、変数に格納せず作成した方がリーダブルかもしれません。

ScriptApp.newTrigger('main').timeBased().everyMinutes(10).create();

公式リファレンスでは、メソッドごとに改行して書かれています。

この方がチェーン記法だということが伝わりやすい人もいるので、改行については、どっちが正しいというわけではありません。

/**
 * Creates two time-driven triggers.
 */
function createTimeDrivenTriggers() {
  // Trigger every 6 hours.
  ScriptApp.newTrigger('myFunction')
      .timeBased()
      .everyHours(6)
      .create();

  // Trigger every Monday at 09:00.
  ScriptApp.newTrigger('myFunction')
      .timeBased()
      .onWeekDay(ScriptApp.WeekDay.MONDAY)
      .atHour(9)
      .create();
}

トリガーから作成できないトリガー

講座内では、GASからトリガーを作成する方法をお伝えしました。

1分おきに発火する時限式トリガーを手動で設置する

1分ごとに、関数printを発火するトリガーを、関数myFunctionを実行して設置します。

/** 時限式トリガーを作成する関数 */
function myFunction() {
  ScriptApp.newTrigger("print").timeBased().everyMinutes(1).create();
}

/** 正常にログ出力しましたと出力する関数 */
function print() {
  console.log('正常にログ出力しました');
}

このような時限式トリガーが設置され、1分起きに発火します。問題ありません。 

1分後に発火する時限式トリガーを手動で設置する

1分後に、関数printを発火するトリガーを、関数myFunctionを実行して設置します。

/** 時限式トリガーを作成する関数 */
function myFunction() {
  const setTime = new Date();
  setTime.setMinutes(setTime.getMinutes() + 1);
  ScriptApp.newTrigger("print").timeBased().at(setTime).create();
}

/** 正常にログ出力しましたと出力する関数 */
function print() {
  console.log('正常にログ出力しました');
}

もちろん、1分後に関数printが実行され、トリガーは有効期限が切れます。 

それでは、関数myFunctionを1分ごとに発火する時限式トリガーを手動で設置するとどうなるでしょう。 

このように、1分後に「1分後に関数printを発火するトリガー」が設置されます。 

実行数を確認すると、関数myFunctionの実行、関数printの実行を1分ごとに繰り返します。 

トリガーは、無効になったものが増え続けます。(この後の説明のために一度すべてのトリガーを手動で削除します) 

1分後に発火する時限式トリガーをGASで設置する

それでは、関数myFunctionを1分ごとに発火する時限式トリガーを、GASで設置してみます。

関数createMyTrrigerを手動で実行します。

/** 時限式トリガーを作成する関数 */
function createMyTrriger() {
  ScriptApp.newTrigger("myFunction").timeBased().everyMinutes(1).create();
}

/** 時限式トリガーを作成する関数 */
function myFunction() {
  const setTime = new Date();
  setTime.setMinutes(setTime.getMinutes() + 1);
  ScriptApp.newTrigger("print").timeBased().at(setTime).create();
}

/** 正常にログ出力しましたと出力する関数 */
function print() {
  console.log('正常にログ出力しました');
}

関数myFunctionを発火するトリガーが設置されます。 

関数printを発火するトリガーが設置されます。 

しかし、関数printを発火するトリガーは無効になってしまいます。

「このトリガーは無効になりました。原因は不明です」とのことです。 

実行数を確認しても、関数printは発火していません。 

これは、V8のバグです。どうやらRhinoランタイムに戻すと実行されるようです。

Attention Required! | Cloudflare

結論:『GASで設置した時限式トリガーから、設置された時限式トリガーは、無効になるバグがある』です。

この回避方法は、「GASで6分の壁を乗り越える」という記事を、後日書こうと思います。

ノンプロ研メンバーが書かれているこちらの記事も参考にしてください。

まとめ

以上で、「Utility services1」 をお届けしました。

繰り返しになりますが、GAS中級講座5期の補講ブログでは、講座内で伝えられなかったTipsをたくさん載せてあります。

ぜひご一読ください。

次回は、 「Utility services2」 をお届けします。

参考資料

Installable Triggers

このシリーズの目次

  1. [ノンプロ研]GAS中級講座6期Day1 スコープと関数
  2. [ノンプロ研]GAS中級講座6期Day2 クラス・ライブラリ
  3. [ノンプロ研]GAS中級講座6期Day3 組み込みオブジェクト
  4. [ノンプロ研]GAS中級講座6期Day4 Utility services1
  5. [ノンプロ研]GAS中級講座6期Day5 Utility services2
  6. [ノンプロ研]GAS中級講座6期Day6 HTTP通信・API
タイトルとURLをコピーしました