記憶力が無い

プログラミングと室内園芸と何か

AppsScript から Drive のファイルに書き込むときはちゃんと書き込まれたか確認が必要(かも?)

AppsScript はつらいよ。。。

AppsScript から Drive のファイルに書き込む

DriveApp を使うことで、 AppsScript から Drive に保存してあるファイルの読み書きができます。

// ファイルの読み書きの例

// ファイルID から ファイルを取得する(xxxx の部分にファイルIDが入る)
const file = DriveApp.getFileById('xxxx');

// ファイルの中身を文字列として取得し、ログに表示する
Logger.log(file.getBlob().getDataAsString());

// ファイルの中身を文字列 'hoge' で上書きする
file.setContent('hoge');

書き込みは必ずしも成功するとは限らない

AppsScript から Drive の操作ができるのはかなり強力な機能ですが、安定性に欠けるところに気を付けなければいけません。

書き込んだはずなのに中身が空っぽ...

AppsScript から Drive に書き込みを行うシステムを構築・運用しているのですが、ファイルが突然空になってシステムが動かなくなるという問題が発生するようになりました。

Drive はファイルの版(変更履歴)が残るので、そこから何とか復旧させることが出来ましたが、復旧後も同じことが頻発したため、システムの動作が困難となりました。

実は過去にもファイルが空になる現象が発生したことはあったのですが、その時は一度きりの発生だったため詳しく調べることはできませんでした。

調査

次のようなプログラムを作成し実行してみました。

function hoge() {
  const file = DriveApp.getFileById('xxxx');
  for (let i = 0; i < 100; i++) {
    Logger.log(file.getBlob().getDataAsString());
    file.setContent('hoge');
  }
}

ファイルの書き込み内容は file.setContent('hoge'); と固定しているので、普通ならファイルが空になることはないはずです。

しかし実行してみると、下の画像の通り、10 ~ 20% くらいの割合で何も表示されない行が出てきてしまいました。

f:id:ttk1:20201029214508p:plain
実行結果

参った。。。

厄介な問題

厄介なことに、書き込みに失敗しているのにも関わらずエラーになってないんですよ。

通常 DriveApp 関連で問題が発生した時は サービスエラー: ドライブ という例外が投げられるのですが、今回は問題なく実行が完了してしまいました。

対策

調査の結果、連続して書き込みに失敗する確率はそこまで高くないようでした。 そのため、今回は書き込み後にちゃんと書き込まれたかチェックする処理と、書き込みに失敗していた場合はリトライする処理を追加することにしました。

// 書き込み後のチェックとリトライ処理の実装例

function writeFile(file, content) {
  for (let i = 0; i < 10; i++) {
    // 書き込みの実行
    file.setContent(content);
    // 書かれた内容のチェック
    if (file.getBlob().getDataAsString() == content) {
      return;
    }
    // 書き込みがうまくいってない場合はちょっと待ってからリトライ
    Utilities.sleep(1000);
  }
  // リトライ回数が上限に達した場合例外を投げる
  throw new Error('書き込み失敗! content: ' + content);
}

経験的には、このような状況は一時的なもので、しばらくすると発生しなくなることが多いです。 しかし、再度発生することもあるため、打てる策は打っておく方が望ましいです。

まとめ

AppsScript はこのように、通常時だと全く問題なく動くのに、ある日突然使い物にならなくなることが割とあります(そして、たいていの場合数時間後に直る)。 なので、たまに数時間(~最悪数日)止まっても許されるようなもの以外では AppsScript を使うべきではないでしょう。

Copyright © 2017 ttk1