アプリ スクリプト 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()