2

アプリ スクリプト Web アプリで興味深い問題が発生しました。起動時とハンドラーで、コードはスプレッドシート A から小さな範囲のデータ (約 20 個の値) を取得しgetRangeByNameます。スプレッドシート A は複雑ではありませんが、4 ページあり、そのうちの 2 ページはスプレッドシート B から読み込まれます ( を使用importRange)。これらの 2 つのページにはそれぞれ 1 つの がロードされ、ImportRangeそれぞれ約 6000 のセルが読み込まれます。

これが問題です。ユーザーが Web アプリの URL をクリックすると、多くの場合 (試行の 25% 程度)、読み込まれたデータgetRangeByNameが正しくありません。返されるデータは#VALUE!、実際のスプレッドシート データではありません。返されるはずだった実際のデータは、リンクされた ( importRange) スプレッドシートから派生したテキスト (個人の名前) です。

これは通常、起動時に発生しますが (の場合doGet)、ユーザーがボタンをクリックした後に発生することもありました。

getRangeByNameスプレッドシートが を介してデータの読み込みを完了する前に が戻るように見えますimportRange。これは実際には大きな問題ではありません。特定のセルが既知の正しい値になるまで、getRangeByNameスクリプトを でループするようにスクリプトを変更しただけです。sleep限られたテストの後、修正は機能しているようです。しかし、これはかなりアマチュアのようです。他の誰かがこれを見たことがありますか?これは既知の問題ですか?これを処理する「適切な」方法はありますか?

最初の編集

スリープ/再読み取りの修正が機能しなかったため、以下のコードを追加しました。openByIdスプレッドシートを開くプレーンの代わりにこれを呼び出します。このコードには、最初は 2 番目のflush呼び出しのみが含まれていました。このコードは、2 回目のスローで失敗することがありますが、これは不可能に見えます。ここで何が起こっているかというと、GAS は (最終的に) for ループ内で正しいスプレッドシート データを取得し、for ループを終了してまったく同じデータをフェッチしようとしますが、データが正しくないということです。

2回目の編集

getRangeByNameコメントで示唆されているように、への最初の呼び出しの前に、以下のコードに 2 番目のフラッシュ操作を追加しました。変わりはない; コードは、(ハンドラー内で) への 3 回目の呼び出しで(再び2 回目のスローで) 失敗しました。InputSpreadsheetOpen

/**
 * Work around what appears to be a Google race condition when opening
 * the input spreadsheet. If we can't read what we expect from a range
 * in the spreadsheet, just sleep and try again.
 */
function InputSpreadsheetOpen() {
  var ss = SpreadsheetApp.openById(INPUT_SS);
  var data;

  SpreadsheetApp.flush();         // should be completely pointless...
  for(var i=0; ; i++) {
    data = ss.getRangeByName("swimmerNames").getValues();
    if(data == null)
      throw(" 'swimmerNames' is not defined."); // spreadsheet error
    if(data[0] == FIRST_NAME)
      break;                                    // got expected value
    if(i <10) {                                 // Google error?
      Utilities.sleep(500);                     // ms; total 5s
      continue;
    } else
      throw("The server appears to be busy. Please refresh the browser page.");
  }

  SpreadsheetApp.flush();         // should be completely pointless...
  data = ss.getRangeByName("swimmerNames").getValues();
  if(data[0] != FIRST_NAME)
    throw("GAS is broken. Reload and pray.");
  return ss;
} // InputSpreadsheetOpen()
4

0 に答える 0