1

I'm trying to implement a simple continuation token using the "Working example (linear iterator)" from this post, but I keep getting a "Exception: Invalid argument: continuationToken" error, not sure how to get around this.

I've tried moving the var userProperties and var continuationToken around from global to to within my deleteFile(), but still no go. Debugger also show that userProperties fills with data, but continuationToken is always null(right before the error). Also not sure why it always jumps down to the else case to fail out, even on first run.

const sheetID = "IDgoeshere"; //sheet with ids and user names 
const sheetName = 'Sheet1' //name of the sheet in the doc
const emailID = Session.getActiveUser().getEmail();
var userProperties = PropertiesService.getUserProperties();
var continuationToken = userProperties.getProperty('CONTINUATION_TOKEN');

function deleteFile() {
  const spreadsheet = SpreadsheetApp.openById(sheetID);
  const sheet = spreadsheet.getSheetByName(sheetName);
  const lastRow = sheet.getLastRow();
  const values = sheet.getRange(2, 4, lastRow - 1, 3).getValues();
  values.forEach((row, index) => {
    const owner = row[0];
    const id = row[2];
    if (continuationToken == null) {  
      if (emailID == row[1]) {
        try {
          var file = DriveApp.getFileById(row[2])
          if (file.isTrashed == true) {
            console.info('was trashed');
            row++;
          }
          else {
            file.setTrashed(true);
          }
        }
        catch (e) {
          console.info(`Unable to find file with id ${id}`);
        }
      }
      else {
        // not the first time, pick up where we left off
        var files = DriveApp.continueFileIterator(continuationToken); ***//errors out here***
      }
    }
    while (files.hasNext() && end.getTime() - start.getTime() <= maxTime) {
      var file = files.next();
      Logger.log(file.getName());
      end = new Date();
    }

    if (files.hasNext()) {
      var continuationToken = files.getContinuationToken();
      userProperties.setProperty('CONTINUATION_TOKEN', continuationToken);
    }
    else {
      // Delete the token
      PropertiesService.getUserProperties().deleteProperty('CONTINUATION_TOKEN');
    }
});
}
Rubén
  • 34,714
  • 9
  • 70
  • 166
levenoples
  • 11
  • 3
  • Where is the previous iterator iterator to continue from? PropertiesService is not an iterator. Please simplify your [mcve] into one function so that it is easier for us to reproduce the problem. Your excessive use of global variables make the code difficult to follow. Make it easier for us and perhaps you will get some help. – Cooper Nov 24 '21 at 16:04
  • Good question: I'm not sure. I just assumed that the working example was working, and tried to appropriate it into my code. Seems it's not fully working then. Should I start off with a "userProperties.setProperty('CONTINUATION_TOKEN', continuationToken);" type line. I've not used continuation tokens before, and TBH my coding leaves a lot to be desired as well. Another assumption I've been working off of is that there is a token that the script starts with and will go from there. If there's not, and one needs to be set, I was unaware of that. EDIT: Got it, reworking to a MRE now. – levenoples Nov 24 '21 at 16:10
  • Got it down to what I think is a good minimal reproducible example. Thanks for the heads up. – levenoples Nov 24 '21 at 18:33

1 Answers1

0

Here's a bit of a contrived example:

function myfunk1(token) {
  const folder = DriveApp.getFolderById(gobj.globals.testfolderid);
  let files;
  if(token == null) {
    files = folder.getFiles();
  } else {
    Logger.log('get continuaton token')
    files = DriveApp.continueFileIterator(token);
  }
  while(files.hasNext) {
    let file = files.next();
    Logger.log(file.getName());
    if(!token ) {
      try {
        myfunk1(files.getContinuationToken())
      }
      catch{
        return;
      }
    }
  }
}

In this example I just broke the processing of an iterator and call the function recursively one time with a continuation token.

Cooper
  • 59,616
  • 6
  • 23
  • 54
  • Ok, if I follow this correctly: 1. I should be able to sub a sheet for const folder, since all my IDs i"m actioning on are in that sheet. 2. If there is no token, it should start performing my deleteFile(), correct? (Essentially marking all items that match executing user's email address as "Trashed" from the above sheet) 3. "else" it'll look for a token left behind by the last execution of that user? 4. "while" it finds another row of fileID, I can getname or .setTrashed(true)? 5. if no token, .getcontinuationtoken() and continue to .setTrashed(true) – levenoples Nov 24 '21 at 21:02
  • Well I don't think you can replace a folder with a sheet. DriveApp has nothing todo with sheets, except for the fact that spreadsheets are files. – Cooper Nov 24 '21 at 21:13
  • Presumeably you have some process that's taking longer than the script can run. So you need to stop it before it fails and then start it again a short time later but you wish to resume it at the same place you ended. The DriveApp.continueFileIterator will allow you to do that as long as you give a valid fileIterator contrinuation token. – Cooper Nov 24 '21 at 21:28
  • Correct, I have more fileIDs than I can trash in one execution. So, I'm trying to figure out where to track the time and how often I should update the token. Do I need to set the token in the PropertiesService under UserProperties, and then check there first before continuing? Something like: userProperties.setProperty('CONTINUATION_TOKEN', continuationToken); – levenoples Nov 24 '21 at 21:51
  • 1
    In your case I don't think you really need to worry about continuation tokens you just need to know what row you you stopped on and begin with that row in the next iteration and yes I think I'd just store it in PropertiesService. – Cooper Nov 24 '21 at 22:14