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 :
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
}
The statement that the server handler function calls aren't independent processes because they "are created from inside the function itself" isn't quite true.
You've set up a checkBox element chk1
with a server handler doSomething
. Whenever the
checkBox is checked, then, an event is dispatched to the server. (...and your script is causing those events with every chk1.setValue()
call) The checkBox
and surrounding UI code is running in your browser - click "show source" or use an explorer to see what's been served to your browser by the google servers. (Warning - it's obfuscated. But you might recognize some of your strings, and from that your client-side code.)
Here's what we're told in the documentation for Class ServerHandler:
When a ServerHandler is invoked, the function it refers to is called on the Apps Script server in a "fresh" script.
That's the key to extending your operating time: each dispatched event results in invocation of doSomething()
in a completely new operating context - it's like you've opened the script editor in a different browser, and clicked "run" on your script. The "fresh" script has no access to var values of previous run... but it is also given it's own set of operating restrictions, including timers.
PS: You should make sure that server-side handler is "thread safe" by using Lock, since you're accessing shared resources that may be accessed by multiple instances of the doSomething()
callback. Related to that, it's possible to hit another limit with this script:
Just for fun, I commented out .setVisible(false)
on chk1
, so the checkBox would be visible. I then rapidly clicked it several dozen times. The time display ran out-of-order, and eventually the above error popped up. (minutes later) It's an artificial situation, of course, but still an error state that's easily avoided.
PPS: I wonder if one could use the same technique to dispatch multiple parallel server-side handlers, and thus reduce the elapsed time to complete the whole job?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With