谷歌驱动权限api仅调用20次后就出现速率限制错误

问题描述 投票:1回答:1

我有一个脚本,它是通过一个文件夹列表并使用Drive权限api转移所有权。我使用那个而不是bean(DriveApp.commands),因为我需要抑制电子邮件通知。

虽然每分钟传输至少100个文件真的应该没问题,但我每3到15个文件就会出错,即使单个调用需要3秒的时间来传输,也就是每分钟只有20个,每分钟40个,因为这可能算作每个文件的两个独立调用。

//SNIPPET
  for (var i = 0; i < records.length; i++) {

    var folder = records[i]; // SPECIFIC FOLDER
    if (folder.Transferred === true) {
      //console.log(total+" That folder already transferred -"+folder.gdrive); 
      continue;
    }
    var target = folder.owner;    
    try {
        var result = passOwner(folder.gdrive, target);
      } catch (e) {
        console.log(e);
        Utilities.sleep(2000);
      }     
  } //for loop

//END OF PROBLEM CODE

function passOwner(fileId, user) {
  if (user == null) return -2;
  try {
    Drive.Permissions.insert({
      'role': 'owner',
      'type': 'user',
      'value': user
    }, fileId, {
      'sendNotificationEmails': 'false'
    });
  } catch (e) {    
    if (e.indexOf("File not found:") > -1) return -1;
    console.log("Taking a nap" + e);
    Utilities.sleep(2000);
    return -1;
  }
  try {
    DriveApp.getFileById(fileId).revokePermissions("[email protected]");
  } catch (e) {
    console.log(e);
    return -1;
  } 
  return 0;
}

带时间戳的调试日志

Jan 31, 2020, 10:34:17 AM Debug TypeError: Cannot find function indexOf in object GoogleJsonResponseException: API call to drive.permissions.insert failed with error: Rate limit exceeded. User message: "These item(s) could not be shared because a rate limit was exceeded: XXXX".
Jan 31, 2020, 10:34:18 AM Debug 88Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:21 AM Debug 89Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:24 AM Debug 90Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:27 AM Debug 91Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:30 AM Debug 92Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:33 AM Debug 93Folder transferred - 1XGOOGLEDRIVEID
Jan 31, 2020, 10:34:34 AM Debug TypeError: Cannot find function indexOf in object GoogleJsonResponseException: API call to drive.permissions.insert failed with error: Rate limit exceeded. User message: "These item(s) could not be shared because a rate limit was exceeded: XXXX".

知道我应该怎么做才能进一步排除故障吗?每次它出现速率限制错误时,我都会让它小睡2秒,没有其他明显的使用api的情况同时发生。最有说服力的是,它几乎是马上就开始速率限制崩溃(在第一次出现问题之前,它的速率限制不到5)。

google-apps-script google-drive-api
1个回答
0
投票

今天,我可以确认,文件的所有者可以通过Drive API的批量请求来改变。因此,我想提出一个示例脚本来实现你的目标,如下。

当使用批量请求时,一个API调用可以运行100个API请求。而且,每个任务都可以用异步进程来运行。这样一来,进程成本和配额成本都可以降低。

示例脚本。

当你使用这个脚本时 请在高级谷歌服务中启用Drive API. 当 records 的脚本,脚本就会变成如下的样子。

function myFunction() {
  // Please set the values of "records".
  const records = [
    {Transferred: false, owner: "###@gmail.com", gdrive: "### fileId 1###"},
    {Transferred: true, owner: "###@gmail.com", gdrive: "### fileId 2###"},
    {Transferred: false, owner: "###@gmail.com", gdrive: "### fileId 3###"},
    ,
    ,
    ,
  ];

  // Create requests for the batch request.
  const requests = records.reduce((ar, {Transferred, owner, gdrive}) => {
    if (Transferred === false) {
      ar.push({
        method: "POST",
        endpoint: `https://www.googleapis.com/drive/v3/files/${gdrive}/permissions?transferOwnership=true`,
        requestBody: {
          role: "owner",
          type: "user",
          emailAddress: owner
        }
      });
    };
    return ar;
  }, []);

  // Run batch requests.
  const limit = 100;
  const split = Math.ceil(requests.length / limit);
  const boundary = "xxxxxxxxxx";
  for (let i = 0; i < split; i++) {
    const object = {batchPath: "batch/drive/v3", requests: requests.splice(0, limit)};
    const payload = object.requests.reduce((s, e, i) => s += "Content-Type: application/http\r\nContent-ID: " + i + "\r\n\r\n" + e.method + " " + e.endpoint + "\r\nContent-Type: application/json; charset=utf-8\r\n\r\n" + JSON.stringify(e.requestBody) + "\r\n--" + boundary + "\r\n", "--" + boundary + "\r\n");
    const params = {method: "post", contentType: "multipart/mixed; boundary=" + boundary, payload: payload, headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}, muteHttpExceptions: true};
    var res = UrlFetchApp.fetch("https://www.googleapis.com/" + object.batchPath, params);
    console.log(res.getContentText())
  }

  // DriveApp.createFile()  // This is used for automatically detected the scope of https://www.googleapis.com/auth/drive. This scope is required to use the method of Permissions: create in Drive API.
}

请注意。

  • 在上面的脚本中,即使在长度为 records 是超过100,脚本工作。
  • sendNotificationEmail=false 使用了,会出现以下错误 The sendNotificationEmail parameter is only applicable for permissions of type 'user' or 'group', and must not be disabled for ownership transfers. 发生。所以在这个剧本中。sendNotificationEmail=false 不使用。

参考资料。

© www.soinside.com 2019 - 2024. All rights reserved.