0

I have a script that will export all of my sheets into separate PDF documents into the folder named Invoices, however it is creating 6 documents and after that I'm getting the error code below, this has been tried on a Gsuite account also and I'm getting the same error:

Exception: Request failed for https://docs.google.com returned code 429. Truncated server response: <meta name="viewport" c... (use muteHttpExceptions option to examine full response)

function savePDFs( optSSId, optSheetId ) {
  var ss = (optSSId) ? SpreadsheetApp.openById(optSSId) : SpreadsheetApp.getActiveSpreadsheet();
  var url = ss.getUrl().replace(/edit$/,'');
  var parents = DriveApp.getFileById(ss.getId()).getParents();
  
  var folders = DriveApp.getFoldersByName('Invoices');  
  var folder = folders.hasNext() ? folders.next() : parents.next(); 

  var sheets = ss.getSheets();
  for (var i=0; i<sheets.length; i++) {
    var sheet = sheets[i];
    if (optSheetId && optSheetId !== sheet.getSheetId()) continue; 
    var url_ext = 'export?exportFormat=pdf&format=pdf'   //export as pdf
      + '&gid=' + sheet.getSheetId()   //the sheet's Id
      // following parameters are optional...
      + '&size=letter'      // paper size
      + '&portrait=true'    // orientation, false for landscape
      + '&fitw=true'        // fit to width, false for actual size
      + '&sheetnames=false&printtitle=false&pagenumbers=false'  //hide optional headers and footers
      + '&gridlines=false'  // hide gridlines
      + '&fzr=false';       // do not repeat row headers (frozen rows) on each page
    var options = {headers: {'Authorization': 'Bearer ' +  ScriptApp.getOAuthToken()}}
    var response = UrlFetchApp.fetch(url + url_ext, options);
    var valor = sheet.getRange('D5').getValue();  // Modified
    var blob = response.getBlob().setName(valor + '.pdf');
    folder.createFile(blob);
  }
}

Any thoughts?

TheMaster
  • 45,448
  • 6
  • 62
  • 85
Excelsson
  • 195
  • 3
  • 16
  • 1
    About `code 429`, The HTTP 429 Too Many Requests response status code indicates the user has sent too many requests in a given amount of time ("rate limiting"). [Ref](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) For example, how about this? Although I'm not sure about your actual situation from your question, if you run the function of `savePDFs` in the loop, how about using `Utilities.sleep(milliseconds)`? – Tanaike Jul 11 '20 at 04:19
  • Related [Rate Limit Error to Nest Thermostat - Response Code 429](https://stackoverflow.com/q/28434686/1595451) – Rubén Jul 11 '20 at 04:41
  • 1
    Does this answer your question? [Creating Multiple Google Sheets PDFs throws 429 error](https://stackoverflow.com/questions/47648338/creating-multiple-google-sheets-pdfs-throws-429-error) – Rubén Jul 11 '20 at 04:49

2 Answers2

3

See my very long answer with a more complicated work-around if execution time is an important factor here

The easier work around:

At the bottom of my answer in the above link, you'll see a reference to the number of seconds that I was able to delay the recursive part of the function to extract any number of PDFs from a sheet indefinitely at 8 seconds, so all you need to do is add the following to your code at the end of the for loop:

Utilities.sleep(8000)

The whole code would be:

function savePDFs( optSSId, optSheetId ) {
  var ss = (optSSId) ? SpreadsheetApp.openById(optSSId) : SpreadsheetApp.getActiveSpreadsheet();
  var url = ss.getUrl().replace(/edit$/,'');
  var parents = DriveApp.getFileById(ss.getId()).getParents();
  
  var folders = DriveApp.getFoldersByName('Invoices');  
  var folder = folders.hasNext() ? folders.next() : parents.next(); 

  var sheets = ss.getSheets();
  for (var i=0; i<sheets.length; i++) {
    var sheet = sheets[i];
    if (optSheetId && optSheetId !== sheet.getSheetId()) continue; 
    var url_ext = 'export?exportFormat=pdf&format=pdf'   //export as pdf
      + '&gid=' + sheet.getSheetId()   //the sheet's Id
      // following parameters are optional...
      + '&size=letter'      // paper size
      + '&portrait=true'    // orientation, false for landscape
      + '&fitw=true'        // fit to width, false for actual size
      + '&sheetnames=false&printtitle=false&pagenumbers=false'  //hide optional headers and footers
      + '&gridlines=false'  // hide gridlines
      + '&fzr=false';       // do not repeat row headers (frozen rows) on each page
    var options = {headers: {'Authorization': 'Bearer ' +  ScriptApp.getOAuthToken()}}
    var response = UrlFetchApp.fetch(url + url_ext, options);
    var valor = sheet.getRange('D5').getValue();  // Modified
    var blob = response.getBlob().setName(valor + '.pdf');
    folder.createFile(blob);
    Utilities.sleep(8000);
  }
}
Rob
  • 555
  • 3
  • 11
  • Since execution time is not a big deal this did it, such a great solution for an easy step to add, thank you Rob – Excelsson Jul 11 '20 at 20:38
1

I found out another work around that is working very well in my case, and it's way faster than the Utilities.sleep method.

What I ended up doing is using the try and catch structure. Under each statement I added the same function to generate the pdfs. SOmething like this:

    try{
        var pdf = generatePDF(sheet);
      } catch(e){
        var pdf = generatePDF(sheet);
      }

So what end up happening is that if you get the 429 error, the code will try once again to run the generatePDF function, and that process will take enough time so that you won't get the too many requests message again.

ghgomes
  • 21
  • 2