スクリプトを実行中は重ねて実行できないようにしたい。
今回ぶつかったケース
- トリガーで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名をメールの本文に記載する