【问题标题】:Service invoked too many times for one day: gmail read一天服务调用次数过多:gmail 读取
【发布时间】:2012-12-21 12:53:02
【问题描述】:

我遇到了 gmail 的各种速率限制,我不确定我能做些什么来解决它们。我想要完成的是在 gmail 中搜索任何带有某些“过期”标签的邮件(以分钟为单位的不同时间)。我的意图是让邮件规则将这些标签应用于在一定时间后变得无关紧要的邮件。我希望这些邮件保留在我的收件箱中,直到它们过期,然后自动存档。我基于在http://googleappsdeveloper.blogspot.com/2011/07/gmail-snooze-with-apps-script.html 看到的帖子中的一般技术

我有一个触发器,它每五分钟运行一次“过期”功能。

因此,它每 5 分钟调用 10 次 GmailApp.getUserLabelByName,并调用 1 次 getThreads()。然后根据它找到多少匹配线程,对于每一个它:

1 x getFirstMessageSubject 1 x getLastMessageDate 1 个添加标签 1 x moveToArchive 1 个移除标签

即每个线程 5 次调用。

所以,我想,我每天要打 10 个电话 / 5 分钟,或者 2880 个电话,只是为了寻找消息。然后,假设我在一天中发现 1,000 条消息,另外还有 5,000 个电话。加起来就是 7,880 个电话,这在我认为的配额限制之下,但我有点不清楚。根据配额限制下的https://docs.google.com/a/macros/latinschool.org/dashboard,对于像我这样的 Google Apps for Edu 帐户,我每天应该能够执行 10,000 次 GMail 读取和 10,000 次 GMail 写入操作。我认为我所有的电话都属于这两者之一。

我可以减少我使用的标签/次数,而不是获取主题(我正在使用它进行调试),但除此之外,我不确定如何使这个脚本更有效率。而且我完全不清楚我是如何达到配额的(参见上面的数学)。

这是我的代码:

/**
 * Expire mail after set time by archiving based on labels
 * based on http://googleappsdeveloper.blogspot.com/2011/07/gmail-snooze-with-apps-script.html
 * For more information on interacting with GMail labels, see
 * https://developers.google.com/apps-script/class_gmaillabel
 */

var expiretimes = [5,15,30,60,120,180,240,480,720];  // times in minutes to expire messages


function getLabelName(i) {
  return "expire/expire " + i;
}

function setup() {
  // Create the labels we’ll need for expiring
  GmailApp.createLabel("expire");
  for (var expt = 0; expt < expiretimes.length; expt++) {
    GmailApp.createLabel(getLabelName(expt));
  }
    GmailApp.createLabel("expired");
}


function expiremsgs(expiremin) {
  // get current date
  var nowdate = new Date();
  Logger.log(nowdate);

  // get the label for given name
  var label = GmailApp.getUserLabelByName(getLabelName(expiremin));
  var expiredlabel = GmailApp.getUserLabelByName("expired");
  var threads = label.getThreads();
  Utilities.sleep(1000);
  for (var i = 0; i < threads.length; i++) {
    Logger.log("i: " + i);
    Logger.log(threads[i].getFirstMessageSubject());
    var lastmsgdate = threads[i].getLastMessageDate();
    Logger.log(lastmsgdate);
    var minold = (nowdate-lastmsgdate)/60000; // convert from ms to minutes
    Logger.log(minold);
    if (minold > expiremin) {
      threads[i].addLabel(expiredlabel);
      threads[i].moveToArchive();
      threads[i].removeLabel(label);
      Logger.log("Archived");
    }
  Utilities.sleep(1500);
  }
};

function expire() {
  for (var expt = 0; expt < expiretimes.length; expt++) {
    expiremsgs(expt);
  }
}

【问题讨论】:

  • 为什么每次通话都要重新搜索消息?获取邮箱中的所有电子邮件并将其过期值存储在您的客户端中的某个地方是否没有意义?这不像早上 9 点检查,发现在下午 1 点过期的邮件,当您在 9:05 再次检查时,会突然具有不同的过期值。
  • 还有其他访问 gmail 的脚本吗?您还可以访问其他访问 gmail 的人编写的脚本。
  • Marc B - 我不想收到收件箱中的所有消息,因为它们可能很多,而且可能会超时。我需要查看每条消息有什么标签,所以我认为这样搜索会最有效。
  • Srik - 不,没有其他脚本在运行。

标签: google-apps-script


【解决方案1】:

我仔细看了看你在做什么,看起来你的数学是正确的。但是,我知道在使用电子表格时使用批处理操作是最佳实践。所以,我查了一下参考资料,发现了几个关键功能:

GmailApp.moveThreadsToArchive(GmailThreads[]);
label.removeFromThreads(GmailThreads[]);
label.addToThreads(GmailThreads[]);

我认为,这些函数将减少您使用 API 进行的读/写调用的次数。 (如果我错了,请 Google OP 纠正我。)

不过,当我在玩你的代码时,我发现这些函数一次只能处理 100 个线程,所以如果超过了,那么操作必须批处理。我还检查了调用 GmailApp 服务的速度和可扩展性,发现大多数调用的延迟与所涉及的项目数量大致无关。至少在我的测试中,批量归档 6 个线程大约需要(在一两秒内)与 100 个相同的时间。在出Gmail之前,我也尽最大努力在脚本中做尽可能多的事情。最后,我修改了您与超时交互的方式。我一生都无法弄清楚你是如何获得数组中的值的,所以我修改了它以及标签。他们现在将读取“expires/in 15min”等。脚本需要大约 30 秒来处理 300 条左右的实际带有标签的消息。

另一种方法可能是运行一次搜索,一次性查找所有标签,然后再检查标签。但是,当您检查每个线程的属性时,这可能仍会向 Gmail 回调太多调用。

所有这些都结束了,这是我对您的代码的迭代:

var expiretimes = [5,15,30,60,120,180,240,480,720];

function getLabelName(i) {
  return "expire/in " + expiretimes[i]  + " min";
}

function setup() {
  GmailApp.createLabel("expired");
  GmailApp.createLabel("expire");
  for (var expt = 0; expt < expiretimes.length; expt++) {
    GmailApp.createLabel(getLabelName(expt));
  }
}

function expire() {
  var allExpThreads = [];
  for (var expt = 0; expt < expiretimes.length; expt++) allExpThreads = allExpThreads.concat(expiremsgs(expt));
  if(allExpThreads.length > 100) batchExpire(allExpThreads);
  else GmailApp.moveThreadsToArchive(allExpThreads).getUserLabelByName("expired").addToThreads(allExpThreads);
}

function expiremsgs(expiremin) {
  var label = GmailApp.getUserLabelByName(getLabelName(expiremin));   
  var threads = label.getThreads();
  if(threads.length > 0){   
    var threadsToExpire = threads.filter(msgExpired, {date: new Date(), min: expiretimes[expiremin]});
    if(threadsToExpire.length > 100) batchRemoveLabel(threadsToExpire,label);
    else if(threadsToExpire.length > 0) label.removeFromThreads(threadsToExpire);
    return threadsToExpire;
  }
  return [];
}

function msgExpired(thread) {
  return this.date - thread.getLastMessageDate() / 6000 > this.min;
}

function batchRemoveLabel(threads,label) {
  var start = 0, end = 100;
  do {
    label.removeFromThreads(threads.slice(start,end));
    start = end;
    end = end > threads.length - 100 ? threads.length : end + 100;
  } while (start < threads.length);
}

function batchExpire(threads) {
  var start = 0, end = 100;
  var expLabel = GmailApp.getUserLabelByName("expired");
  do {
    GmailApp.moveThreadsToArchive(threads.slice(start,end));
    expLabel.addToThreads(threads.slice(start,end));
    start = end;
    end = end > threads.length - 100 ? threads.length : end + 100;
  } while (start < threads.length);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多