Behind this (not so much I admit...) funny question is a real question about a workaround I use without really understanding how it works.
First a brief description of my use case, all this is happening in a document bound UiApp showing up in the sidebar :
I have to create and send by email a couple of hundred documents in a mail merge application written in GAS. It takes of course far too long to be processed in one batch without hitting the 5 minutes execution time limit so I tried a few different workarounds to get the task done :
- use a time stamp (stored in ScriptProperties) when I start the process and when I reach a predefined value near the limit I store the current values (pointers, useful vars...) and return to the user interface asking the user to continue (or not). That works pretty well but need a human action to complete the whole task.
- So I setup a solution using a timer trigger that I create in the first handler call and this trigger calls the doc creation / sending function. This is also working nicely but the trigger called function are not able to interact with the UI since it seems that only handler functions can update the UI. The problem there is that I cannot show the progress nor easily show when the process ends.
- Then I remembered a small app that a wrote some time ago just for fun : it was a timer that used a checkBox as a server handler trigger (from an idea suggested long ago by Romain Vialard on the old Google forum) and decided to try this trick in my mail sending process.
It works perfectly, I process 40 documents batches is each call (during about 3 minutes) then pause for a while and start again until it gets finished. Each call is triggered by the checkBox linked server handler, the check box itself is changed in the handler function, creating its own trigger this way.
My question (finally ;-) is : knowing that the whole process might take 30 to 60 minutes how precisely is that possible ? How / why are these server handler function considered as multiple process since they are created from inside the function itself ?
I hope I'm clear enough, (which I doubt since it is a bit confuse in my mind :-)
I join below the code of the clock test app that gave me the idea, it will probably make things easier to understand.
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
}