よく使うTime Triggerのテンプレ

Google Apps Script Advent Calendar七日目です。
そろそろキツイですね☆

ということで今日はTime Triggerのお話をします。

GASのとても便利な機能としてTime Triggerがあります。
これは特定の日時や、期間でGASを起動するものです。

実際に触っている方はわかると思いますが、とても便利です。
便利ですが自動再起動がなかったり、完了通知は自前だったり面倒臭いところもあります。

ということで僕が会社向けにつくっているバッチでよく使っているTime Triggerを利用したバッチのテンプレを以下に書きます。

# よく使うTime Triggerのテンプレ

```javascript:TimeTriggerのテンプレ
function timeTriggerのテンプレでっせ() {
  
  var start = Moment.moment();
  
  TiggerUtil.deleteTrigger();
  
  var lastExecuteCount = parseInt(ScriptProperties.getProperty("lastExecuteCount") || "0");
  
  //lastExecuteCountを使ってデータの取得とか
  var データ = getデータ(lastExecuteCount);
  
  for(var i = 0; i < データ.length; i++) {
    
    var errorCount = 0;

    while(true) {

      try {

        でっかい処理(データ[i]);
        
        break;
        
      } catch(e) {
        Logger.log(e);
        errorCount++;
        
        if(errorCount > 5) {
          saveLastExecute(lastExecuteCount);
          //レジューム処理
          Logger.warning("なんかよく失敗しているのでちょっと経ってから起動します。");
          TriggerUtil.resumeTrigger(aruments.callee.name);
          MailApp.sendEmail(Session.getEffectiveUser().getEmail(), "hogehoge処理のエラー回数が閾値を超えたので少し経ってから再起動します。" , Logger.getLog());
        }
      }
    }
    
    lastExecuteCount++;
    if(TriggerUtil.isNearlyTimeOut()) {
      saveLastExecute(lastExecuteCount);
      //レジューム処理
      Logger.log("5分経過したので処理を再起動します。");
      TriggerUtil.resumeTrigger(aruments.callee.name);
      MailApp.sendEmail(Session.getEffectiveUser().getEmail(),"hogehoge処理を再起動します。"  , Logger.getLog());
    }
  
  
  }
  
}

function saveLastExecute(lastExecuteCount) {
  ScriptProperties.setProperty("lastExecuteCount" , lastExecuteCount);
}

(function(global){
  var TriggerUtil = {
    
    
    DEFAULT_TRIGGER_KEY : "triggerId",
    DEFAULT_INTERVAL_MINUTES : 1,
    DEFAULT_TIMEOUT_MENUTES: 5,
    
    
    /**
     * タイムアウトに近いか?
     * @param {Moment} startMoment 処理開始時の時間(Momentオブジェクト)
     */
    isNearlyTimeOut : function(startMoment) {
      return Moment.moment().diff(startMoment , "m") >= this.DEFAULT_TIMEOUT_MENUTES;
    },
    
    /**
     * 渡されたTriggerKeyで保存されているTriggerを削除
     * @param {string} triggerKey (非必須)ScriptPropertiesに保存されているTriggerIdのKey名  渡されない場合はDEFAULT_TRIGGER_KEYの値になる。
     */
    deleteTrigger : function(triggerKey) {
      triggerKey = triggerKey || this.DEFAULT_TRIGGER_KEY;
      var triggerId = ScriptProperties.getProperty(triggerKey);
      
      if(!triggerId) {
        return;
      }
      
      ScriptApp.getScriptTriggers().filter(function(trigger){
        //var trigger = ScriptApp.getScriptTriggers()[0];
        return trigger.getUniqueId() == triggerId;
      })
      .forEach(function(trigger) {
        ScriptApp.deleteTrigger(trigger);
      });
      
      ScriptProperties.deleteProperty(triggerKey);
    },
    
    
    /**
     * 渡されたfunctionNameを再起動
     * @param {object} option (オプション) triggerKeyとintervalMinutesを設定する。
     */
    resumeTrigger : function(functionName , option) {
      if(!functionName) {
        throw new Error("Given functionName");
      }
      
      var options = option || {};
      
      var triggerKey = options.triggerKey || this.DEFAULT_TRIGGER_KEY;
      var intervalMinutes = options.intervalMinutes || this.DEFAULT_INTERVAL_MINUTES;
      
      var triggerId =
          ScriptApp.newTrigger(functionName).timeBased().at(Moment.moment().add("m" ,intervalMinutes ).toDate()).create().getUniqueId();
      
      ScriptProperties.setProperty(triggerKey, triggerId);
    
    }
    
    
  }
  global.TriggerUtil = TriggerUtil;
  
})(this);
```

長いですが以下のような機能を持ってます。

* タイムアウト時の再起動
* エラー時のリトライ(ロジックレベルと、TimeTriggerレベル)
* エラー時、リトライ時はメール送信

もちろんバッチの種類によって細かいところは変えます。
参考にしてみてください。


.....
5日連チャンでネタが無くなったわけじゃないんだからね(;ﾟ∀ﾟ)=3ﾊｧﾊｧ
細かい解説は元気があったら追記します。。。。。。多分

### 追記
微妙に間違えていたところを直しました...