電波ビーチ

☆(ゝω・)v

Google Apps Scriptでスクリプト内から時間ベースのトリガーを作成する

そういうのをやりたかったが、無限に「このトリガーは無効になりました。原因は不明です。」とかいうのが出るんですよねこれが

ググった

zenn.dev

  • V8ランタイムのバグ
  • V8オフにするといける
  • あるいは実行権限廻りのバグ?
  • Webアプリケーションとしてデプロイして、アプリ内から呼べばV8でもいける

なるほど、素晴らしい!V8ランタイムをオフにするのは嫌なので、Webアプリケーションからの起動を試してみよう!

ここではミニマムで、とりあえず『1分おきにA1のセルが時刻で変更される』ということにしてみる。

何はともあれまずは適当なSpreadSheetのコンテナバインドスクリプトを作成し、設定からV8とappscript.jsonをオンにする。

んで以下のコード。ES6以降の構文をガンガン使っていこう

appscript.json

{
  "timeZone": "Asia/Tokyo",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "webapp": {
    "executeAs": "USER_DEPLOYING",
    "access": "MYSELF"
  }
}

code.gs

/**
 * V8でtriggerをスクリプト内部で作成してtimebasedする
 * 一度webアプリとしてデプロイする必要があるし、そのデプロイの中で実行する必要がある
 * これは初回だけ起動すればいいやつ
 * (あとからデプロイを取り消してもそのまま動き続けた。ただしあとから追加した処理は当然動かなかった)
 */
const SS = SpreadsheetApp.getActive();
const triggers = ScriptApp.getScriptTriggers();
const triggerName = "minituesOnTime";

/**
 * 1分ごとに現在の時間でA1を書き換えるだけ
 */
function minituesOnTime() {
  console.log("--- START---");
  const sheet = SS.getActiveSheet();

  /**
   * 関数名を決め打ちで消す箇所
   */
  for(let trigger of triggers){
    if(trigger.getHandlerFunction() === triggerName){
      ScriptApp.deleteTrigger(trigger);
    }
  }
  const now = new Date();
  const time = Utilities.formatDate(now, "Asia/Tokyo", "HH時mm分ss秒");
  console.log(`now ${time}`);
  const range = sheet.getRange(1, 1); // どこでもいいけどな
  range.setValue(time);

  const next = new Date(Utilities.formatDate(now, "Asia/Tokyo", "yyyy/MM/dd HH:mm"));
  next.setMinutes(next.getMinutes()+1); // 1分後にセット
  console.log(`next: ${next}`);
  ScriptApp.newTrigger(triggerName).timeBased().at(next).create();
}


/**
 * ちゃんとhtml返さないと動かなかった
 */
function doGet(){
  console.log("WELCOME HTML");
  const html = HtmlService.createTemplateFromFile("index");
  return html.evaluate();
}

index.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <div id="content"></div>
    <?!= HtmlService.createHtmlOutputFromFile("js").getContent(); ?>
  </body>
</html>

js.html

<script>
  const content = document.getElementById("content");
  const element = document.createElement("div"); 
  element.id = "base"; 
  element.style.opacity = "0.3";
  element.textContent = "LETS GO...."";
 content.appendChild(element);
  // HTMLからGASの関数を叩く
  google.script.run.withSuccessHandler(() => {
    element.style.opacity = "1";
    element.textContent = "処理が完了しました";
  }).withFailureHandler((err)=>{
    element.textContent = "SOMETHING ERROR!!!";
    alert(`エラー:やり直してください ${err}`);
  }).minituesOnTime();
</script>

Webアプリとしてデプロイしてアクセス

アクセスするタイミングではうまくトリガーがセットされないことがある(秒数がゼロなせい?)のでそのときはもっかいどうぞ

これでSpreadSheetが時間ベースのトリガーでいじれるようになりました。やったね!以下はログ。

コード内のコメントにも書いてあるけど、一度デプロイしたらそのデプロイを削除しても動き続いた。デプロイしたあとマニュアルでコードから実行するとどうなるかは試してないのでわからない。