检查触发器执行当前是否正在 Google Apps 脚本中运行

check if a trigger execution is currently running in Google Apps Scripts

提问人:IMTheNachoMan 提问时间:10/7/2019 更新时间:11/23/2021 访问量:4876

问:

是否可以查看特定项目的触发器是否有任何活动/正在运行的执行?

我有一个一次性迁移脚本/项目,用于将数千个 Google 表格文件更新为新的模板格式。根据我的计算,该脚本将需要数小时才能运行。我们的 G-Suite Enterprise 环境的执行时间限制为 30 分钟。

我的代码是这样编写的,如果脚本失败,无论出于何种原因,我都可以重新运行它,它将从停止的地方继续。

有时,脚本会因其他原因(如内存错误或网络连接问题)而失败。

因此,我想设置一个 15 分钟的触发器来运行脚本。我希望它检查另一个执行是否仍在运行。如果是,那么它就会停止。如果不是,那么它将继续。

我知道如何使用来查看链接到项目的触发器,但我不知道如何找到正在运行的执行。ScriptApp.getProjectTriggers()

谷歌应用脚本

评论

3赞 Sourabh Choraria 10/7/2019
直接在控制台上检查它们怎么样?script.google.com/home/executions
0赞 IMTheNachoMan 10/7/2019
我不想在电脑前。如果我可以通过编程方式进行检查,我可以自动执行整个过程,并在完成后给我发电子邮件。

答:

5赞 Tanaike 10/7/2019 #1
  • 您想知道脚本现在是否由时间驱动的触发器运行。
  • 您希望使用 Google Apps 脚本来实现此目的。

如果我的理解是正确的,那么这个答案怎么样?请把这看作是几个答案之一。

溶液:

我认为您可以使用 Google Apps Script API 中的 processes.list 方法实现您的目标。当 Google Apps 脚本 API 中的 processes.list 方法在脚本由时间驱动的触发器运行期间被请求时,可以检索以下值。

{
 "processes": [
  {
   "projectName": "sampleProject",
   "functionName": "myFunction",
   "processType": "TIME_DRIVEN",
   "processStatus": "RUNNING",  // <--- here
   "userAccessLevel": "OWNER",
   "startTime": "2019-10-07T00:00:00.000Z",
   "duration": "36.145s"
  }
 ]
}

在本例中,是 .脚本完成后,processStatus 将更改为 COMPLETEDprocessStatusRUNNING

检索 when is 信息的示例脚本如下。processStatusRUNNING

用法:

1. 将云平台项目链接到 Google Apps 脚本项目

在这种情况下,需要将 Cloud Platform Project 链接到 Google Apps Script Project。关于如何链接它,你可以在这里看到它。

2. 启用 Google Apps 脚本 API

第二步,请在 API 控制台中启用 Google Apps Script API。关于如何启用它,您可以在此线程中看到它。

3. 运行示例脚本:

function sample() {
  var scriptId = "###"; // Please set the script ID here.
  var functionName = "###"; // Please set the function name here.

  var url = "https://script.googleapis.com/v1/processes?userProcessFilter.functionName=" + functionName + "&userProcessFilter.scriptId=" + scriptId;
  var res = UrlFetchApp.fetch(url, {headers: {Authorization: 'Bearer ' + ScriptApp.getOAuthToken()}});
  var obj = JSON.parse(res);
  var runningScript = obj.processes.filter(function(p) {return p.processType == "TIME_DRIVEN" && p.processStatus == "RUNNING"});
  Logger.log(runningScript)
}
  • 使用此脚本时,请添加 和 的范围。因此,请将它们添加到清单文件()。https://www.googleapis.com/auth/script.external_requesthttps://www.googleapis.com/auth/script.processesappsscript.json
  • 使用此脚本时,请设置触发时间驱动触发器时运行的变量和变量。scriptIdfunctionName
  • 在此脚本中,当没有正在运行的 scrit 时,将返回。[]
  • 如果您想了解其他工艺类型,请修改 .p.processType == "TIME_DRIVEN"

注意:

  • 我认为在您的情况下,您还可以使用方法:processes.listScriptProcesses
  • 根据我的经验,当脚本完成时,有时会出现.但在这种情况下,它表示脚本已完成。processStatusUNKNOWN

引用:

如果我误解了你的问题,这不是你想要的方向,我很抱歉。

添加:

我认为使用Apps Script API的方法是一种解决方案。为了在不将云平台项目链接到 GAS 项目的情况下实现您的目标,在这里,我想提出一个解决方法。

在此解决方法中,我使用了 Drive API 的属性。使用云端硬盘 API 的属性时,可以将该属性检索到其他项目。所以在这里,我使用了Drive API的属性。请将此视为几种解决方法之一。

用法:

1. 在高级 Google 服务中启用 Drive API

首先,请在 Advanced Google 服务中启用 Drive API。

2. 示例脚本:

示例脚本 1:

请复制并粘贴以下脚本。它假设 的函数由时间驱动的触发器运行。runByTrigger

function runByTrigger(e) {
  var fileId = "###"; // Please set the file ID.

  if (e && "triggerUid" in e && e.triggerUid != "") {
    Drive.Files.update({properties: [
      {key: "processStatus", value: "RUNNING", visibility: "PUBLIC"},
      {key: "processStartTime", value: new Date().toISOString(), visibility: "PUBLIC"},
    ]}, fileId);
  }

  // do something
  // Here, please put your script.

  if (e && "triggerUid" in e && e.triggerUid != "") {
    Drive.Files.update({properties: [
      {key: "processStatus", value: "COMPLETED", visibility: "PUBLIC"},
      {key: "processStartTime", value: "", visibility: "PUBLIC"},
    ]}, fileId);
  }
}

示例脚本 2:

此脚本用于检查脚本是否由时间驱动的触发器运行。请运行此脚本进行检查。您也可以使用此脚本,该脚本与包括 .runByTrigger

function myFunction() {
  var fileId = "###"; // Please set the file ID.

  var runningScript = Drive.Properties.get(fileId, "processStatus", {visibility: "PUBLIC"}).value;
  if (runningScript == "RUNNING") {
    var startTime = Drive.Properties.get(fileId, "processStartTime", {visibility: "PUBLIC"}).value;
    Logger.log("Script is currently running. Start time is %s", startTime)
  } else {
    Logger.log("Script was finished.")
  }
}
  • 脚本 1 和 2 是同一个 ID。作为测试用例,如果脚本是独立脚本,请设置独立脚本的脚本 ID。如果脚本是容器绑定脚本,请设置 Google Docs 的文件 ID。fileId
  • When 由时间驱动的触发器运行,并放入文件的属性中。runByTriggerprocessStatusprocessStartTime
    • 如果脚本当前正在运行,则在运行函数时,日志中会显示。myFunctionScript is currently running. Start time is {startTime}
    • 如果脚本已完成但未运行,则显示在日志中。Script was finished.

注意:

  • 在此解决方法中,将使用 file 的属性。但我认为,例如,流程状态也可以保存到电子表格等。

引用:

评论

0赞 IMTheNachoMan 10/7/2019
这太棒了。这似乎需要一个 GCP 项目,但我无法创建一个。我的公司使用 G-Suite Enterprise,GCP 项目被阻止。我必须使用默认的来做所有事情。:/
1赞 Tanaike 10/7/2019
@IMTheNachoMan 感谢您的回复。对于给您带来的不便,我深表歉意。我没有注意到您无法将云平台项目链接到 GAS 项目。所以我又添加了一种方法。这是在 Advanced Google 服务中使用 Drive API 的解决方法。如果这对您的情况没有用,我再次道歉。
0赞 IMTheNachoMan 10/9/2019
这看起来很有希望。让我试试看。
0赞 Rivo 10/19/2020
@Tanaike我知道这可能跑题了,但是当一个函数由触发器运行时,怎么知道呢?我想将此信息记录到电子表格中,这样我就可以记录调用函数时它是否由触发器运行(例如由 Web 应用程序运行,由编辑器运行,如 GAS 仪表板 - 我的执行选项卡 - 类型列所示)。
1赞 shamisen 3/15/2021
@Tanaike 感谢您的优雅解决方案!关于你的第一种方法,我认为它应该是而不是.var obj = JSON.parse(res.getContentText());var obj = JSON.parse(res);
4赞 Hell-K 11/23/2021 #2

这是最干净(同时也是最简单)的方法:

Google 为 Apps 脚本提供了一个内置工具,称为锁定服务。您可以使用它来避免在代码仍在运行时再次运行代码的任何部分(由您手动或通过触发器)。

只需将要从触发器调用的函数结构化为:

function functionName() {
  let lock = LockService.getUserLock().tryLock(0);
  if (lock.hasLock()) {
    // Your code goes here.
  };
};

现在,每当您的扳机触发时,它都会首先检查是否有锁。如果有,它将跳过该运行。如果没有,它将创建一个锁并开始执行您的代码。