最近APIまわりのスクリプトで、トリガーを設定して自動実行させるスクリプトが増えてきました。今までは面倒であまりエラー処理を実装していなかったのですが、後からメールで来るエラー通知をみてから修正や再実行するのも面倒になってきたので、 これを機会ににエラー処理を実装します。
組み込みたい機能としては
- 実行に失敗したときに新しいトリガーをもう一度セットしたい
- エラーの通知をSlackに出したい
の2点です。
try…catch構文を使う
Google Apps Script(以下GAS)でのエラー処理といえば、try…catch構文です。MDNのサイトに以下のサンプルスクリプトが記載されています。
try {
nonExistentFunction();
} catch (error) {
console.error(error);
// expected output: ReferenceError: nonExistentFunction is not defined
// Note - error messages will vary depending on browser
}
tryブロック内で、nonExistentFunction()というその名前の通りの存在しない関数を実行しようとしているので、エラーとなりcatchブロック内の処理が実行されます。
その際、エラー情報を格納したErrorオブジェクトが生成されるので、それを任意の仮引数(上記の例だとerror)で受け取って、ログ出力などのエラー発生時の処理を実行します。
エラー発生時には新しいトリガーを6時間後にセットする
まず、実行したい処理を書いた関数を用意します。今回はmainFunction()としました。
mainFunction()のエラー発生時にトリガーを再設定するためにtry…catch構文を用います。tryブロックにmainFunction()の実行、catchブロックにトリガー再設定のスクリプトを用意します。
先に完成形のスクリプトをご紹介しておきます。
function triggerMainFunction() {
try {
mainFunction();
} catch (error) {
ScriptApp.newTrigger('triggerMainFunction')
.timeBased()
.after(6 * 60 * 60 * 1000)
.create();
}
}
GASで新しいトリガーを作成するには、ScriptAppクラスのnewTrigger(functionName)メソッドを利用します。文字通り新しいトリガーを作成するメソッドです。
newTrigger(functionName)メソッドの戻り値はTriggerBuilderオブジェクトで、このTriggerBuilderオブジェクトの各メソッドを用いて、具体的なトリガーの設定を指定します。
まずtimeBased()メソッドで時間ベースのトリガーとし、さらにその戻り値であるClockTriggerBuilderオブジェクトで使用できるafter(durationMilliseconds)メソッドで何ミリ秒後にトリガーをセットするかを指定します。
ここまで読んで嫌になった方いますよね。わかります。
この「オブジェクト > メソッド > 戻り値 > オブジェクト」のループを整理できるかでGASでできることは増えるので、頑張りましょう。
- newTrigger(functionName)メソッド > TriggerBuilderオブジェクト
- timeBased()メソッド > ClockTriggerBuilderオブジェクト
- after(durationMilliseconds)メソッド > ClockTriggerBuilderオブジェクト
- create()メソッド > Triggerオブジェクト
と、今回はトリガーを作成するまでに何段階かのオブジェクトを経過していってます。ただ、スクリプトで書くと以外とシンプルです。
ScriptApp.newTrigger('mainFunction') // TriggerBuilderが戻り値
.timeBased() // TriggerBuilder > ClockTriggerBuilder
.after(6 * 60 * 60 * 1000) // ClockTriggerBuilder > ClockTriggerBuilder
.create(); // ClockTriggerBuilder > Trigger
after(durationMilliseconds)メソッドの引数ですが、スクリプトの実行時刻から何ミリ秒経過後に指定した時間ベーストリガーを実行するかを指定します。
今回は6時間後としたかったので 1000ミリ秒の60倍(60秒)の60倍(60分)の6倍(6時間)を指定しました。
.after(6 * 60 * 60 * 1000) // 6時間後に実行させる
Slackに通知させる
Slackへの通知は、以下の記事にて紹介しました。
記事内のpostText2Slack_()関数を今回も利用します。
function postText2Slack_(postText, webhookUrl) {
const params = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify({ text: postText }) // JSON形式の文字列に変換
};
UrlFetchApp.fetch(webhookUrl, params);
}
Errorオブジェクトのエラーメッセージを格納しているmessage
プロパティをそのまま投稿しましょう。
function triggerMainFunction() {
try {
mainFunction();
} catch (error) {
ScriptApp.newTrigger('triggerMainFunction')
.timeBased()
.after(6 * 60 * 60 * 1000)
.create();
const webhookUrl = '指定チャンネルのWebhook URL';
postText2Slack_(error.message, webhookUrl);
}
}
おわりに
これでエラーが発生した時にSlackに通知しつつ6時間後に再度実行を試みるという仕様になります。
エラーの内容がAPIのサーバーエラーなどのリトライで解決しそうな場合は、そのまま放置して6時間後の再実行を待ち、スクリプトの修正が必要そうであれば修正するという判断が、Slackへの通知を起点に検討できます。
Google Apps Scriptを勉強したい方へ
この記事を見て、GASを勉強したいなと思われた方はぜひノンプログラマーのためのスキルアップ研究会(通称 ノンプロ研)にご参加ください。私も未経験からこの学習コミュニティに参加し、講座を受講したことでGASが書けるようになりました。
学習コミュニティ「ノンプログラマーのためのスキルアップ研究会」
挫折しがちなプログラミングの学習も、コミュニティの力で継続できます。ノンプロ研でお待ちしております!