Google Apps Scriptの限界を越えよう
GASでは、実行時間6分の壁があります。
でっかい処理を行ったときに、タイムアウトするというやつですね。
本稿では、タイムアウトする前にいったん処理を中止して、トリガーセットで再度実行させるという方式で立ち向かってみます。
と、その前に
こういうやり方もありますよ、とお見せする前に。
- 余計なAPI呼び出ししてないですか?
- 無意味なデータ読み書き
- 冗長なAPI呼び出ししてないですか?
- データ読み書きがまとまっていない
- それ、まじでGASでやる必要ありますか?
データの読み書きにフォーカスしているのは、非エンジニアにとってスプレッドシートを触る機会が圧倒的に多く、かつGASの中でシートデータの読み書きは 圧倒的に時間がかかる からです。
正直、計算とかはすぐ終わります。数秒です。
読み書きはデータの大きさによっては数分かかります。
不死鳥のように蘇らせよう
道具
- スクリプトのプロパティ
スクリプトには、それぞれデータを溜めておけるデータストア的なものがあります。
スクリプトのプロパティというやつです。こいつを使って、実行を中断するときの必要情報を残しておきます。
@tanabee様のGAS ビギナーが GAS を使いこなすために知るべきこと 10 選 - スクリプトトリガー
実行イメージ
- スクリプトのプロパティから必要な値を引っ張ってくる
- 関数実行開始時間を取得
- ループ
- 現在時刻の取得
- difference = { 現在時刻 - 実行開始時刻 }
- ◯分経過しているか
- している
スクリプトプロパティの更新を行う
次回実行のためのトリガーの設定 - していない
処理を行う
- している
- ループ後処理(必要なら)
- スクリプトプロパティの初期化
- トリガーの削除(しないと永遠に回り続けるぞ?)
スクリプト例
/*
* GAS5分実行を越える!!
* スクリプトプロパティを活用
*/
function phoenix(){
var properties
= PropertiesService.getScriptProperties();
// 例はint
var prop
= parseInt( properties.getProperty("<name_of_property>") );
// 関数実行時点の時刻取得
var start_time = new Date();
for( i ){
// 現在時刻を取得する
var current_time = new Date();
// 実行時間取得
var difference
= parseInt( (current_time.getTime() - start_time.getTime()) / (1000 * 60) );
//4分を超えていたら中断処理
if(difference >= 4){
/* 値の書き込みとか必要ならやる */
// スクリプトプロパティの更新
properties.setProperty("<name_of_property>",i);
// ここはもうちょっと利口なやり方がありそう。
ScriptApp
.newTrigger("phoenix")
.timeBased()
.everyMinutes(5)
.create();
return ;
}else{
/* 通常処理 */
}//if_escape
}//ループ処理
// スクリプトプロパティの初期化
properties.setProperty("<name_of_property>",<initial_value>);
//特定関数のトリガーのみ削除
delete_specific_triggers("phoenix");
return ;
}//func_phoenix
// 特定関数のトリガーを全て削除
function delete_specific_triggers( name_function ){
var all_triggers = ScriptApp.getProjectTriggers();
for( var i = 0; i < all_triggers.length; ++i ){
if( all_triggers[i].getHandlerFunction() == name_function )
ScriptApp.deleteTrigger(all_triggers[i]);
}//for_i
}//func_deleteSpecificTriggers
備考
もっと利口なやり方があると思われますので、編集リクエストお待ちしております。
Class ClockTriggerBuilder - afterとかうまくつかえないかなぁ。