【GAS】特定の時間内だけ実行する方法

前回の記事でNotionデータベース内の特定のプロパティに変化があったらSlackへ通知するGASを作ったんですが、1分おきに実行するトリガーを設定しているためGASが1日あたり1×60*24で1440回も実行されてしまうことになります。

1回あたりの実行時間は0.5~3秒くらいなのですが、塵も積もれば山となる…

GoogleAppsScriptでは、「〇時~〇時の間だけ実行する」というトリガーは作れないので、スクリプト側で作成する必要があるようです。

9時~18時だけ動くようにしてGASの負担を減らしたい……

てことでネットの海をさまよっていたら、対処方法を見つけたのでメモします。

参考になったサイト

以下サイトがとても参考になったので先にご紹介しておきます。

トリガーの仕組み

01
トリガーにsetTriggerだけ用意しておく
setTriggerを実行するためのトリガー
02
毎日、0:00~1:00に翌朝9:00に実行する関数(startTrigger)のトリガーを自動生成
startTriggerを実行するためのトリガー
03
9:00になったら本丸の関数(main)を実行するためのトリガーを自動生成
mainを実行するためのトリガー
04
18:00になったらstartTrigger、mainのトリガーをリセットする
startTrigger、setTriggerを削除
05
02以降を繰り返す…

こんな感じでトリガーとスクリプトを駆使して疑似的に開始~終了時間を指定しています。

作り方

1.スクリプトを書く

// ①月~金の0~1時ごろに「朝9:00に起動するトリガー」を生成
function setTrigger() {
  const time = new Date();
  const week = /[1-5]/; //月曜~金曜を判定するための正規表現 日曜:0~土曜:6

  //実行した日が月曜~金曜ならStartTriggerをセット
  if (week.test(time.getDay())) {
    time.setHours(09);
    time.setMinutes(00);
    ScriptApp.newTrigger("startTrigger").timeBased().at(time).create();
  }
}

// ②9:00になったら毎分おきにSlack通知するトリガーを生成
function startTrigger() {
  ScriptApp.newTrigger("main").timeBased().everyMinutes(1).create();
}

// ③18時になったらsetTrigger、startTriggerを削除する
function delTrigger() {
  const time = new Date();
  if (time.getHours() >= 18) {
    const triggers = ScriptApp.getProjectTriggers();
    for (const trigger of triggers) {
       if (["startTrigger", "main"].includes(trigger.getHandlerFunction())) {
        ScriptApp.deleteTrigger(trigger);
      }
    }

  }
}

main関数に追記する

function main() {
....(実行内容)
.......
delTrigger();
}

2.トリガーを設定する

設定するトリガーは「setTrigger」1個だけです。

setTrigger。これだけセットしておけばあとは何もしなくていい
setTrigger。トリガーはこれだけセットしておけばあとは何もしなくていい
実行する関数

setTriggerを選択します。

イベントソース・タイプ・時刻

時間主導型の日付ベース、午前0~1時を選択します。

スクリプトの解説

①setTrigger

毎日深夜0~1時に「翌日の朝9:00に実行するトリガー」を生成するためのトリガーです。
このトリガーを実行すると、こんなトリガーが自動で作成されます。

自動生成されるトリガー
2/6日の0:00~1:00の間に、2/6 9:00に実行するためのトリガーが作られるってコト
const time = new Date();
const week = /[1-5]/;

現在の日付(time)と1-5の正規表現(week)を作成しています。
weekは曜日で、日曜:0~土曜:6です。この場合月曜~金曜をあらわしています。

  if (week.test(time.getDay())) {
    time.setHours(09);
    time.setMinutes(00);
    ScriptApp.newTrigger("startTrigger").timeBased().at(time).create();
  }
  • if (week.test(time.getDay()))で現在の日付の曜日(time.getDay())が指定した曜日1~5(week)に合致しているかどうかを判定しています。
  • time.setHours(09);time.setMinutes(00);は9:00を指定しています。
  • 「ScriptApp.newTrigger("startTrigger").timeBased().at(time).create();ここで「startTrigger」関数を9:00に1回実行するタイマーが作られます。

つまり

  • 「1-5」の曜日(月曜日から金曜日)の時だけ
  • 毎日9:00に「startTrigger」関数が実行される

ということです。

②startTrigger

月~金の朝9:00になると、こんなトリガーが自動で作成されます。

本命のトリガーがきた

startTriggerの内容を見てみます。

function startTrigger() {
  ScriptApp.newTrigger("main").timeBased().everyMinutes(1).create();
}

※mainは自分が作成した関数名を入れてください。
mainという関数を作成し、everyMinutes(1)で1分ごとに実行するように設定しています。

③delTrigger

delTriggerは、18時以降にトリガーを削除する関数です。

function delTrigger() {
  const time = new Date();
  if (time.getHours() >= 18) {
    const triggers = ScriptApp.getProjectTriggers();
    for (const trigger of triggers) {
       if (["startTrigger", "main"].includes(trigger.getHandlerFunction())) {
        ScriptApp.deleteTrigger(trigger);
      }
    }
  }
}
どうして削除するの
「main」のトリガーを削除することで、毎分おきに実行している関数を18時以降は停止させてるよ
  • const time = new Date();で現在時刻を取得し、if (time.getHours() >= 18)で現在時刻が18時以降かどうか判定しています。
  • 18時以降であれば、ScriptApp.getProjectTriggers()という関数を使って、このスクリプトに設定されているすべてのトリガーを取得します。
  • 取得したトリガーに対して、for (const trigger of triggers)で繰り返し処理を行います。
  • ["startTrigger", "main"].includes(trigger.getHandlerFunction())というコードは、トリガーが「startTrigger」または「main」という関数を持っているかどうかを判定しています。
  • startTrigger・mainを持っていた場合はScriptApp.deleteTrigger(trigger)という関数を使ってトリガーを削除し、すべての処理が終わったらfor文を終了します。

以上です

開始~終了時間設定するだけでこんなに難解とはおもいませんでしたが、ひとまず作れてよかったです☺