Exponential Backoff

153 views
Skip to first unread message

Andrea Bonamici

unread,
Apr 5, 2019, 7:20:12 AM4/5/19
to Google Apps Script Community
Dear all.
I need an help if it's possible.

I've a function that write some contact in Google Contact.
Sometimes the funcion return this error:
{ "error": { "code": 503, "message": "The service is currently unavailable.", "status": "UNAVAILABLE" }

I read that to prevent this type of error is reccomended to use Exponential Backoff.

I'm trying ....without success. 
can I ask for your help?

I execute exec_1 function.

function exec_1() {
var partial_import = call(createContact(2,19));
};

//Exponential Backoff
function call(func) {
  for (var n=0; n<6; n++) {
    try {
      return func();
     } catch(e) {
       if (n == 5) {
         throw e;
       } 
    Utilities.sleep((Math.pow(2,n)*1000) + (Math.round(Math.random() * 1000)));
    }    
  }
}

function createContact(startRow,numRows) {
var GroupName = "SharedContact";  //Name of contact label
var sheet = SpreadsheetApp.getActiveSheet();
    var group = ContactsApp.getContactGroup(GroupName);
    
  // Fetch the range 
  var dataRange = sheet.getRange(startRow, 1, numRows, 8);

  
  // Fetch values for each row in the Range.
  var data = dataRange.getValues();
    for (var i = 0; i < data.length; ++i) {
var row = data[i];
var firstName = row[0];
    
// Se la riga ha valore FirstName vuoto esce dallo script 
if (firstName == 0) return;
                           
var lastName = row[1];
var emailAddress = row[2];
var phone = row[3];
var company = row[4];
var notes = row[5];
var address = row[6];
var DeleteContact = row[7];

      
// Create contact in Google Contacts
if (DeleteContact != "Yes") {
var contact = ContactsApp.createContact(firstName, lastName, emailAddress);
// Add values to new contact
contact.addCompany(company, "");
contact.addPhone(ContactsApp.Field.WORK_PHONE, phone);
contact.setNotes(notes);
contact.addAddress(address, address);
contact.addToGroup(group);
};
     
    };
};



The error is
TypeError: func is not a function, is undefined. 
The error is in row 7 of function call---> throw e;)

Could some good soul help me?
Thank you all
Andrea

ChiefChippy2 is awesome

unread,
Apr 5, 2019, 7:49:18 AM4/5/19
to Google Apps Script Community
On Friday, April 5, 2019 at 1:20:12 PM UTC+2, Andrea Bonamici wrote:
> Dear all.
> I need an help if it's possible.
>
>
> I've a function that write some contact in Google Contact.
> Sometimes the funcion return this error:
> { "error": { "code": 503, "message": "The service is currently unavailable.", "status": "UNAVAILABLE" }
>
>
> I read that to prevent this type of error is reccomended to use Exponential Backoff.
>
>
> I'm trying ....without success. 
> can I ask for your help?
>
>
> I execute exec_1 function.
>
>
> function exec_1() {
> var partial_import = call(createContact(2,19));
> };
>
>
> //Exponential Backoff
> function call(func) {
>   for (var n=0; n<6; n++) {
>     try {
>       return func;
Remove the ()

Jasper Duizendstra

unread,
Apr 5, 2019, 7:50:17 AM4/5/19
to Google Apps Script Community
The erros states that func is not a function. This is because you execute createContact(2,19) when you run  call(createContact(2,19)).
So instead of passing the function you pass the function result of the execution of createContact(2,19).

This can be tricky, you want to pass parameters to createContact. this can be doen by having createContact returning a function like :
function createContact(startRow,numRows) 
   return function() {
   ...

  }
}

This way createContact(startRow,numRows) will return a function when you you run  call(createContact(2,19))

The main issue is, returning a function instead of the function result.

Andrea Bonamici

unread,
Apr 5, 2019, 9:14:44 AM4/5/19
to Google Apps Script Community
Thanks for your answers.
You are very kind.

@Jasper thank you. Your answer made it clear to me why an error is generated.
Unfortunately I did some testing but am unable to implement the code correctly :(

@ChiefChippy2 Thank you. I'm doing tests like you suggested. 
Unfortunately I am not able to tell if the function Exponential Backoff (function called call) is working properly.


bye and have a good day
Andrea

On Friday, 5 April 2019 13:20:12 UTC+2, Andrea Bonamici wrote:

Stéphane Giron

unread,
Apr 5, 2019, 11:24:28 AM4/5/19
to Google Apps Script Community
Hi

You can try that 
var partial_import = call(function(){return createContact(2,19) ;});

Stéphane

Romain Vialard

unread,
Apr 5, 2019, 11:48:05 AM4/5/19
to Google Apps Script Community
I would advise to restrict the use of Exponential Backoff on the specific calls / lines of code needing it.
Here you have added an Exponential Backoff on your whole function, which contains a loop. So if a contact creation fails during the loop the Exponential Backoff will re-execute everything from scratch, creating duplicated contacts.

It would be better to limit to the contact creation call (if it's the line of code throwing errors):
var contact = call(function(){return ContactsApp.createContact(firstName, lastName, emailAddress);});

If you want to try, I created an Apps Script library to handle retries when needed:
It can be used in exactly the same way:
var contact = ErrorHandler.expBackoff(function(){return ContactsApp.createContact(firstName, lastName, emailAddress);});

It automatically log errors in Stackdriver Logging (which you can access via the menu View in the Apps Script editor) so you will know when a retry was needed. And it only perform retries when it makes sense: if the same line of code throws an error on which there's no need to retry, it won't (eg: because you want to create a contact with an invalid email address and ContactsApp prevent you to do that).

Andrea Bonamici

unread,
Apr 5, 2019, 12:00:11 PM4/5/19
to Google Apps Script Community
Many thanks !!!!
As soon as I can do tests I will let you know the outcome.
super nice !!!!!

Best regards
Andrea

On Friday, 5 April 2019 13:20:12 UTC+2, Andrea Bonamici wrote:

andreabon...@gmail.com

unread,
Apr 11, 2019, 8:19:34 AM4/11/19
to Google Apps Script Community
Hi Romain. Sorry if i still bother you.
I'm losing hope.

I did some tests using your App script library (many compliment!) . 
Unfortunately I can't solve the execution problems
Please can you help me to understand  what I'm wrong?
Thank you very much for your valuable help.

Andrea

//This is the call to the function-->
function exec_8() {
createContact(1751,250);
};


//This is the createContact function-->
function createContact(startRow,numRows) {  

var GroupName = "SharedContact";  //Name of contact label
var sheet = SpreadsheetApp.getActiveSheet();
    var group = ContactsApp.getContactGroup(GroupName);
    
  // Fetch the range 
  var dataRange = sheet.getRange(startRow, 1, numRows, 8);

  
  // Fetch values for each row in the Range.
  var data = dataRange.getValues();
    for (var i = 0; i < data.length; ++i) {
var row = data[i];
var firstName = row[0];
    
// IF  FirstName CELL IS EMPTY EXIT SCRIPT
if (firstName == 0) return;
                           
var lastName = row[1];
var emailAddress = row[2];
var phone = row[3];
var company = row[4];
var notes = row[5];
var address = row[6];
var DeleteContact = row[7];  // IF THIS CELL IS POPULATED WHIT YES CONTACT WILL NOT IMPORTED

      
// Create contact in Google Contacts
if (DeleteContact != "Yes") {
//THIS THE EXACT CODE THAT USE EXP BACKOFF. IS CORRECT ?
            var contact = ErrorHandler.expBackoff(function(){return ContactsApp.createContact(firstName, lastName, emailAddress);});
            
ErrorHandler.expBackoff(function(){return contact.addCompany(company, "");});
ErrorHandler.expBackoff(function(){return contact.addPhone(ContactsApp.Field.WORK_PHONE, phone);});
ErrorHandler.expBackoff(function(){return contact.setNotes(notes);});
ErrorHandler.expBackoff(function(){return contact.addAddress(address, address);});
ErrorHandler.expBackoff(function(){return contact.addToGroup(group);});
};
     
    };
};

// Ciao Andrea
Reply all
Reply to author
Forward
0 new messages