スクリプトを実行中は重ねて実行できないようにしたい。
今回ぶつかったケース
- トリガーで1分おきに実行する関数を設定していて
- その関数の処理が1分以内に終わらないことがあり
- 1分後、前回の処理が完了しないうちに次のトリガーが発動して
- 意図しない挙動になってしまう
これを回避するためにスクリプトのプロパティを利用しました。
- 実行中はtrueを入れて重複実行しそうになったら重複実行せず1分待つ
- 実行後はfalseを入れてすぐに次の関数を実行できるようにしておく
LockService でもできそうな感じでしたが、先に思いついたこの方法で、やりたいことは実現できたのでそのコードを書き残しておきます。
コード.gs
/************************************
初回実行
************************************/
function initialize() {
mailNotification(ScriptApp.getScriptId(), '処理を開始します: ');
set_property('running', true);
set_property('count', 0);
createTriggerEvery1Minutes();
}
/************************************
トリガーを作成する
************************************/
function createTriggerEvery1Minutes() {
ScriptApp.newTrigger('run')
.timeBased()
.everyMinutes(1)
.create();
}
/************************************
トリガーで実行する関数
************************************/
function run() {
if(getProps('running') === 'true') {
mailNotification(ScriptApp.getScriptId(), '前回の処理が終わっていないので次の1分を待ちます' + new Date());
} else {
mailNotification(ScriptApp.getScriptId(), '前回の処理が終わっているので実行します' + new Date());
set_property('running', true);
Utilities.sleep(70000);
var count = parseInt(getProps('count'));
if(count === 3) {
deleteTrigger('run');
mailNotification(ScriptApp.getScriptId(), '処理が完了したよ: ');
} else {
set_property('count', count + 1);
mailNotification(ScriptApp.getScriptId(), '処理を開始するよ: ');
}
set_property('running', false);
}
}
/************************************
完了時にGmailで通知する
************************************/
function mailNotification(script_id, message) {
var mail = Session.getActiveUser().getEmail();
var file_name = DriveApp.getFileById(script_id).getName();
MailApp.sendEmail(mail, message + file_name, 'https://script.google.com/macros/d/' + script_id + '/edit?usp=drive_web');
}
/************************************
指定したトリガーを削除する
************************************/
function deleteTrigger(functionName) {
var allTriggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < allTriggers.length; i++) {
if (allTriggers[i].getHandlerFunction() == functionName) {
ScriptApp.deleteTrigger(allTriggers[i]);
break;
}
}
}
/************************************
スクリプトのプロパティを読み書きする
************************************/
var ScriptProperties = PropertiesService.getScriptProperties();
function getProps(id) {
return ScriptProperties.getProperty(id)
}
function set_property(key, value){
ScriptProperties.setProperty(key, value);
}
|
意訳
この機能がやること
メールで開始通知します
スクリプトのプロパティのrunningにtrueを入れます
スクリプトのプロパティのcountに0を入れます
トリガーをセットする関数を実行します
この機能がやること
新しくトリガーでrunという関数を
時間ベースで
1分毎に
作成します
この機能がやること
スクリプトのプロパティのrunningがtrueなら
指定したメッセージをメールに送る
trueでなければ
指定したメッセージをメールに送る
スクリプトのプロパティにtrueを入れる
時間のかかる処理を実行する(この例では70秒間ただただ待つ処理)
スクリプトのプロパティのcountを見て
3なら
トリガーからrunを削除して
指定したメッセージをメールに送る
3じゃなければ
スクリプトのプロパティのcountに+1して入れる
指定したメッセージをメールに送る
スクリプトのプロパティのrunnningにfalseを入れる
この機能がやること
実行しているユーザのemailを取得して
実行しているスクリプトのファイル名を取得して
Gmailを送る(宛先のアドレス, メッセージ+ファイル名, ファイルのURL)
この異能がやること
すべてのトリガーを取得して
トリガーの数だけ繰り返す
もし実行する関数名が渡されたものと一致したら
そのトリガーを削除して
for文から抜ける
スクリプトのプロパティを取得する
この機能がやること
渡されたidの値を返す
この機能がやること
渡されたkeyとvalueでプロパティに保存する
|
関連記事
1時間毎に実行するトリガーをスクリプトで書きたい
1分おきのトリガーを作って5分経ったらトリガーを全部消す
トリガー(不要になったもの)をスクリプトで削除する
ScriptPropertiesを読み書きしてみる
ユーザのGmailアドレスを取得する
スクリプトからmailを送信する
実行したスクリプトのURLとfunction名をメールの本文に記載する