Loop with a timeout that runs only once "as needed"

I wrote a script that restores calendar data from a backup written in a spreadsheet. Since the amount of data is extremely unpredictable, I developed a cycle that stops after a given number of minutes, asking the user to continue or cancel , showing the actual state of the counter (this prevents the problem with the maximum Google max execution time).

This works very well, but in this simplified test script that I used to test the idea, it works only once: when the first "timeout" occurs, it shows the continue/cancel option, as expected, and then continues from there places where it was started but when the same condition occurs a second time , the continue button is not displayed.

My question is simple: why? or better: what's the difference between both situations?

A spreadsheet with an inline script publicly checked here (see menu : test )

and the whole script is shown below (this is a little longer, of course, but the interesting part is closer to the end)

I used ScriptProperties to track the runtime and continue the loop I left.

 function onOpen() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var menuEntries = [ {name: "test", functionName: "test"}, ]; ss.addMenu("test", menuEntries); } function test(){ ScriptProperties.setProperty('restorePointers',[0,0].join('@')) var app = UiApp.createApplication().setTitle("test"); app.setHeight(150).setWidth(250); var doc = SpreadsheetApp.getActiveSpreadsheet(); var panel = app.createVerticalPanel(); var handlerCancel = app.createServerHandler('canceltest'); var handlerContinue = app.createServerHandler('continuetest'); var contCHandler = app.createClientHandler(); var cancel = app.createButton("cancel.", handlerCancel).setId('cancel').setVisible(false); var cont = app.createButton('continue',handlerContinue).setId('continue').setVisible(false).addClickHandler(contCHandler); var button = app.createButton('start').setId('button'); var handler = app.createServerClickHandler('runtest'); handler.addCallbackElement(panel); contCHandler.forTargets(button).setEnabled(false).forEventSource().setVisible(false); var cHandler = app.createClientHandler().forTargets(cancel).setVisible(true).forEventSource().setVisible(false); button.addClickHandler(handler).addClickHandler(cHandler); app.add(panel.add(button).add(cont).add(cancel))//.add(trig)); doc.show(app); } function canceltest(e){ var app = UiApp.getActiveApplication(); ScriptProperties.setProperty('restoreData','') ScriptProperties.setProperty('restorePointers','canceled'); SpreadsheetApp.getActiveSpreadsheet().toast(' ','restore aborted'); app.close() return app; } function continuetest(e){ runtest(e) } function runtest(e){ var dStart; var dEnd; ScriptProperties.setProperty('startrestore',new Date().getTime().toString()) if(ScriptProperties.getProperty('restoreData')==null||Utilities.jsonStringify(ScriptProperties.getProperties()).indexOf('restoreData')==-1) {ScriptProperties.setProperty('restoreData',Utilities.jsonStringify(e)) } var app = UiApp.getActiveApplication(); var pointers = ScriptProperties.getProperty('restorePointers'); if(pointers==' 0@0 '){ dStart = 0; dEnd = 500; }else{ dStart = Number(pointers.split('@')[0]); dEnd = Number(pointers.split('@')[1]); } // main loop -------------------------- for(var ee=dStart;ee<dEnd;++ee){ // main loop var ccc = ScriptProperties.getProperty('restorePointers'); if(ccc=='canceled'){ app.close();return app}; Utilities.sleep(85); // simulate some activity if((ee/10)==parseInt(ee/10)&&ee>0){ SpreadsheetApp.getActiveSpreadsheet().toast(ee+' steps completed') if(new Date().getTime()-Number(ScriptProperties.getProperty('startrestore'))>12000){ ;// +- 12 sec timeout ScriptProperties.setProperty('restorePointers',[ee,dEnd].join('@')); app.getElementById('continue').setHTML('continue from '+ee).setVisible(true) return app } } } // end of main loop----------------- ScriptProperties.setProperty('restoreData','') ScriptProperties.setProperty('restorePointers',0+'@'+0); SpreadsheetApp.getActiveSpreadsheet().toast('normal process end'); app.close(); return app; } 
+4
source share
1 answer

Here, what keeps the β€œcontinue” button from updating at every interval. Your server handler should return the application:

 function continuetest(e){ return runtest(e) ///<<< } 

This bit (ee/10)==parseInt(ee/10) is an inconvenient way to evaluate true every 10th element. Use the module instead:

 if((ee%10==0)&&ee>0){ ///<<< modulus 

After each pause, the ee value is repeated in the toast. This can be eliminated by remembering what the last displayed value is and skipping it.

 if (ee == Number(ScriptProperties.getProperty('lastToast'))) continue; ///<<< don't repeat toast ScriptProperties.setProperty('lastToast',ee); ///<<< 

Full script

 function onOpen() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var menuEntries = [ {name: "test", functionName: "test"}, ]; ss.addMenu("test", menuEntries); } function test(){ ScriptProperties.setProperty('restorePointers',[0,0].join('@')) var app = UiApp.createApplication().setTitle("test"); app.setHeight(150).setWidth(250); var doc = SpreadsheetApp.getActiveSpreadsheet(); var panel = app.createVerticalPanel(); var handlerCancel = app.createServerHandler('canceltest'); var handlerContinue = app.createServerHandler('continuetest'); var contCHandler = app.createClientHandler(); var cancel = app.createButton("cancel.", handlerCancel).setId('cancel').setVisible(false); var cont = app.createButton('continue',handlerContinue).setId('continue').setVisible(false).addClickHandler(contCHandler); var start = app.createButton('start').setId('start'); var handler = app.createServerClickHandler('runtest'); handler.addCallbackElement(panel); contCHandler.forTargets(start).setEnabled(false).forEventSource().setVisible(false); var cHandler = app.createClientHandler().forTargets(cancel).setVisible(true).forEventSource().setVisible(false); start.addClickHandler(handler).addClickHandler(cHandler); app.add(panel.add(start).add(cont).add(cancel))//.add(trig)); doc.show(app); } function canceltest(e){ var app = UiApp.getActiveApplication(); ScriptProperties.setProperty('restoreData','') ScriptProperties.setProperty('restorePointers','canceled'); SpreadsheetApp.getActiveSpreadsheet().toast(' ','restore aborted'); app.close() return app; } function continuetest(e){ return runtest(e) ///<<< } function runtest(e){ var dStart; var dEnd; ScriptProperties.setProperty('startrestore',new Date().getTime().toString()) if(ScriptProperties.getProperty('restoreData')==null||Utilities.jsonStringify(ScriptProperties.getProperties()).indexOf('restoreData')==-1) {ScriptProperties.setProperty('restoreData',Utilities.jsonStringify(e)) } var app = UiApp.getActiveApplication(); var pointers = ScriptProperties.getProperty('restorePointers'); if(pointers==' 0@0 '){ dStart = 0; dEnd = 500; }else{ dStart = Number(pointers.split('@')[0]); dEnd = Number(pointers.split('@')[1]); } // main loop -------------------------- for(var ee=dStart;ee<dEnd;++ee){ // main loop var ccc = ScriptProperties.getProperty('restorePointers'); if(ccc=='canceled'){ app.close();return app}; Utilities.sleep(85); // simulate some activity if((ee%10==0)&&ee>0){ ///<<< modulus if (ee == Number(ScriptProperties.getProperty('lastToast'))) continue; ///<<< don't repeat toast ScriptProperties.setProperty('lastToast',ee); ///<<< SpreadsheetApp.getActiveSpreadsheet().toast(ee+' steps completed') if(new Date().getTime()-Number(ScriptProperties.getProperty('startrestore'))>12000) { // +- 12 sec timeout ScriptProperties.setProperty('restorePointers',[ee,dEnd].join('@')); app.getElementById('continue').setHTML('continue from '+ee).setVisible(true) return app } } } // end of main loop----------------- ScriptProperties.setProperty('restoreData','') ScriptProperties.setProperty('restorePointers',0+'@'+0); SpreadsheetApp.getActiveSpreadsheet().toast('normal process end'); app.close(); return app; } 
+2
source

Source: https://habr.com/ru/post/1480762/


All Articles