簡體   English   中英

當我在GAS中“睡覺”時會發生什么? (執行時間限制解決方法)

[英]What happens when I “sleep” in GAS ? (execution time limit workaround)

在這背后(不是我承認......)有趣的問題是關於我使用的解決方法的真正問題,而沒有真正理解它是如何工作的。

首先簡要介紹一下我的用例,這一切都發生在側邊欄中顯示的文檔綁定UiApp中:

我必須在用GAS編寫的郵件合並應用程序中通過電子郵件創建和發送幾百個文檔。 當然,在沒有達到5分鍾執行時間限制的情況下,在一個批處理中花費太長時間,所以我嘗試了幾個不同的解決方法來完成任務:

  1. 當我啟動進程時使用時間戳(存儲在ScriptProperties中),當我達到接近極限的預定義值時,我存儲當前值(指針,有用的變量......)並返回用戶界面,要求用戶繼續(或不)。 這很有效但需要人工操作來完成整個任務。
  2. 所以我使用我在第一個處理程序調用中創建的計時器觸發器來設置解決方案,此觸發器調用doc創建/發送功能。 這也很好用,但是被稱為函數的觸發器無法與UI交互,因為似乎只有處理函數可以更新UI。 問題在於,我無法顯示進度,也無法在流程結束時輕松顯示。
  3. 然后我想起了一段時間前寫的一個小應用程序只是為了好玩:它是一個使用checkBox作為服務器處理程序觸發器的計時器(來自很久以前Romain Vialard在舊Google論壇上提出的想法)並決定嘗試這個在我的郵件發送過程中的技巧。

它工作得很好,我處理40個文件批次是每次調用(大約3分鍾)然后暫停一段時間並重新開始直到它完成。 每個調用都由checkBox鏈接服務器處理程序觸發,復選框本身在處理程序函數中更改,以這種方式創建自己的觸發器。

我的問題(最后;-)是:知道整個過程可能需要30到60分鍾,這可能有多精確? 這些服務器處理函數如何/為什么被視為多個進程,因為它們是從函數本身內部創建的?

我希望我足夠清楚,(我懷疑,因為它在我的腦海里有點混亂:-)

我加入了時鍾測試應用程序的代碼,它給了我這個想法,它可能會讓事情更容易理解。

function doGet() {
  var app = UiApp.createApplication().setTitle('Counter/Timer');
  var Panel = app.createAbsolutePanel().setStyleAttribute('padding','35');
  var counter = app.createHTML().setId('counter').setHTML('<B>Timer = wait</B>').setStyleAttribute('fontSize','40px');// set start display
  var clo = app.createTextBox().setName('clo').setId('clo').setValue('0').setVisible(false);//set start value in seconds
  var handler1 = app.createServerHandler('doSomething').addCallbackElement(Panel);
  var chk1 = app.createCheckBox('test1').addValueChangeHandler(handler1).setVisible(true).setId('chk1').setVisible(false);
  app.add(Panel.add(chk1).add(counter).add(clo));
  chk1.setValue(true,true);// start the process
  return app}

function doSomething(e) {
  var app = UiApp.getActiveApplication();
  var xx = Number(e.parameter.clo);
  var disp = app.getElementById('counter')
  xx++ ;// replace by xx-- to count downwards
  if(xx>600){ // 10 minutes timeout for example
  disp.setHTML('<B> GAME OVER ;-)</B>').setStyleAttribute('fontSize','80px').setStyleAttribute('color','RED')
  return app
  }
  var cnt = app.getElementById('clo').setValue(xx)
  disp.setHTML('<B>'+T(xx)+'</B>')
  Utilities.sleep(1000); // instead of sleeping do something !
// below comes the "active" part
  var chk1 = app.getElementById('chk1').setValue(false,false)
  var chk1 = app.getElementById('chk1').setValue(true,true)
  return app;
}

function T(val){
  var min = parseInt(val/60);
  var sec = val-(60*min);
  if(sec<10){sec='0'+sec}
  if(min<10){min='0'+min}
  var st = '>  '+min+':'+sec
  return st
}

在此輸入圖像描述

服務器處理程序函數調用的語句不是獨立進程,因為它們“是從函數本身內部創建的”並不完全正確。

您已經使用服務器處理程序doSomething設置了一個checkBox元素chk1 每當選中checkBox時,都會將一個事件分派給服務器。 (...並且您的腳本在每次chk1.setValue()調用時都會導致這些事件) checkBox和周圍的UI代碼在您的瀏覽器中運行 - 單擊“顯示源”或使用資源管理器查看chk1.setValue()瀏覽器提供的內容谷歌服務器。 (警告 - 它被混淆了。但你可能會認識到你的一些字符串,以及你的客戶端代碼。)

以下是我們在Class ServerHandler的文檔中所說的內容

當調用ServerHandler時,它引用的函數在Apps腳本服務器上以“新鮮”腳本調用。

這是延長操作時間的關鍵:每個調度事件都會導致在全新的操作上下文中調用doSomething() - 就像您在其他瀏覽器中打開腳本編輯器一樣,並在腳本上單擊“運行”。 “新鮮”腳本無法訪問以前運行的var值...但它也有自己的一組操作限制,包括計時器。

PS:您應該通過使用Lock確保服務器端處理程序是“線程安全的”,因為您正在訪問可由多個doSomething()回調實例訪問的共享資源。 與此相關,可以使用此腳本達到另一個限制:

截圖 - 錯誤

為了好玩,我在chk1上注釋了.setVisible(false) ,因此checkBox是可見的。 然后我快速點擊了幾十次。 時間顯示無序運行,最終出現上述錯誤。 (幾分鍾后)當然,這是一個人為的情況,但仍然是一個容易避免的錯誤狀態。

PPS:我想知道是否可以使用相同的技術來分派多個並行服務器端處理程序,從而減少完成整個作業所用的時間?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM