google apps script - Loop with timeout protection that only runs once "as it should" -
i wrote script restores calendar data backup written in spreadsheet. since amount of data highly unpredictable designed loop stops after given number of minutes , asking user continue
or cancel
while showing actual counter state (this prevent issue google max execution time limit).
it works pretty in simplified test script used testing idea works once : when first "timeout" occurs, shows continue/cancel
option expected , continues started when same condition happens second time continue
button doesn't shows up.
my question : why ? or better : what's difference between both situations ?
the spreadsheet embedded script publicly testable here (see menu : test
)
and whole script shown below (it's bit long of course interresting part near end)
i used scriptproperties
keep track of execution time , continue loop 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 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 '+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; }
here's what's keeping 'continue' button updating each interval. server handler needs return app:
function continuetest(e){ return runtest(e) ///<<< }
this bit, (ee/10)==parseint(ee/10)
awkward way evaluate true
every 10th item. use modulus instead:
if((ee%10==0)&&ee>0){ ///<<< modulus
after each pause, value of ee repeated in toast. can fixed remembering last displayed value was, , 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 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 '+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; }
Comments
Post a Comment