How many requests a second can you throw at your Google Apps Script webapp

There was a question on the Google Apps Script Community the other day. It went something like this.

When a script is deployed as a web service, executed by the owner, how many requests can it handle each second, as in the example below

This is an important question, because if you have a webapp, potentially used by many people – is it going to run out of some kind of quota and start to fail.

Here’s a simple webapp. I’m going to throw as much as I can at it by making asynchronous requests from a few instances.

function doGet(e) {
  return ContentService
    .createTextOutput (e.parameter.callback + “(” +
       JSON.stringify(
         {thread:e.parameter.thread,
           instance:e.parameter.instance,
           time:new Date().getTime()}) + “);” )
     .setMimeType(ContentService.MimeType.JAVASCRIPT);
}

The results

I can get about 35 responses per second before consistently getting
Script invoked too many times per second for this Google user account.

The conclusion

You’ll need to always use exponential backoff when running popular webapps. You can find a snippet for that here.

Here’s the code for the test. I’m making asynchronous jsonp requests, and reporting the results with a Google Viz table.






    https://www.google.com/jsapi
   
    “use strict”; 
    // write the results to a viz table
      google.load(“visualization”, “1”, {packages:[“table”]});

var GASWEBAPP = “https://script.google.com/a/macros/mcpher.com/s/AKfycbzOVk8SG2ZojmNYwcUiboMAnQ2HPDUyu3qpkqdwegcX/dev”;
var NUMBEROFREQUESTS = 100;
var url = GASWEBAPP + “?thread=” + generateUniqueString(), results = [];

// do a bunch of requests
for (var i =0; i < NUMBEROFREQUESTS ;i++ ) {
slimJSONP (url + “&instance=” + generateUniqueString(), response);
}

// handle the response
function response (result) {
results.push(result);
// report the results
if (results.length === NUMBEROFREQUESTS) {
// we’re done – turn it into a google viz table fordisplaying
google.setOnLoadCallback( function () {
var data =  new google.visualization.DataTable();
Object.keys(results[0]).forEach(function(d) {
data.addColumn (typeof results[0][d], d);
});
data.addRows(results.sort(function(a,b) { return a.time-b.time }).map(function(d) {
return Object.keys(d).map (function(e){
return d[e];
});
}));
                                       new google.visualization.Table (document.getElementById(‘table’)).draw(data);
});
}
}

/**
* do a simple async JSONP 
* @param {string} url the url
* @param {function} done what to callback  when done
* @return {DOMelement} the script element where it was stored
*/
function slimJSONP (url,done) {
// easy jsonp
var script = document.createElement(‘script’);
// html5 supports async script tags
script.async = true;
script.src = url + (url.match(/.*\?/) ? “&” : “?”) + “callback=” + done.name; 
document.body.appendChild(script);
}

/** 
* generateUniqueString
* get a unique string
* @param {number} optAbcLength the length of the alphabetic prefix
* @return {string} a unique string
**/
function generateUniqueString (optAbcLength) {
  var abcLength = typeof optAbcLength === ‘undefined’ ? 3 : optAbcLength;
  return arbitraryString(abcLength) + (new Date().getTime()).toString(36);
 
  function arbitraryString (length) {
 var s = ”;
 for (var i = 0; i < length; i++) {
   s += String.fromCharCode(randBetween ( 97,122));
 }
 return s;
}
function randBetween(min, max) {
  return Math.floor(Math.random() * (max – min + 1)) + min;
}
}
 



For more like this, visit the desktop liberation site, or follow me on g+, and join the Google Apps Script Community.

Author: bm082975

Leave a Reply

Your email address will not be published. Required fields are marked *