建構啟動條件

本文說明如何建構啟動器,讓應用程式或服務在發生事件時通知 Google Workspace Studio,並啟動流程執行作業。在 API 中,啟動器稱為 workflowTriggers

啟動條件會啟動流程,而步驟則是流程中一連串工作中的單一工作。建立啟動條件後,使用者就能設定自動化流程,根據應用程式或服務的即時事件做出反應。

如要建構啟動器,請在外掛程式資訊清單檔案中宣告啟動器,並在 Google Apps Script 中實作生命週期回呼,或是將酬載張貼至 Google Workspace Studio API 端點,藉此觸發啟動器。

先決條件和 OAuth 授權

如要與 Workspace Studio API 端點通訊,應用程式或服務必須使用 OAuth 2.0 進行驗證。應用程式必須在授權期間,向使用者要求下列專屬 OAuth 範圍:

https://www.googleapis.com/auth/workspace.studio.trigger

這個範圍會授權應用程式呼叫 Workspace Studio API,並觸發使用者為該啟動條件設定的工作流程。

離線存取權和更新權杖

因為啟動器會在外部服務發生事件時非同步通知 Workspace Studio,而這可能在使用者設定流程後數小時、數天或數月發生,因此服務在呼叫 API 端點時,必須提供有效的 OAuth 2.0 存取權杖。

外掛程式事件物件 (例如在啟動器設定或生命週期回呼要求期間) 中,Google 提供的存取權杖效期較短,只有 1 小時。日後無法用於非同步觸發啟動事件。如要長期呼叫 Workspace Studio API,您的服務需要離線更新權杖,才能視需要產生新的存取權杖。

授權處理方式和取得更新權杖的方式,取決於外掛程式執行階段:

  • HTTP 外掛程式 (替代執行階段):如果是 HTTP 外掛程式,後端服務必須實作獨立於內建外掛程式授權的 OAuth 2.0 授權流程,才能要求離線存取權 (access_type=offline) 並接收更新權杖。

    當使用者在 Workspace Studio 中設定啟動條件時,您可以顯示登入或授權資訊卡,提示使用者授權這項連線。如要進一步瞭解如何傳回授權卡片及處理 OAuth 流程,請參閱「將 Google Workspace 外掛程式連結至第三方服務」(將 Google Workspace 視為要連結的第三方服務)。

    後端服務必須安全地儲存更新權杖 (例如儲存在服務的資料庫中,與 triggerId 放在一起),並在發生事件時使用該權杖擷取新的存取權杖,然後再將要求傳送至啟動者的 notifyUritriggers.fire API 端點。

  • Google Apps Script 外掛程式: 如果外掛程式是以 Google Apps Script 為基礎,並使用排程 (時間驅動) 觸發條件輪詢事件,則可略過實作獨立的 OAuth 流程。由於排定時間的觸發條件會直接在 Google Apps Script 執行階段環境中執行,因此 Google Apps Script 會使用資訊清單中宣告的範圍,自動管理及重新整理 OAuth 權杖。

在資訊清單檔案中定義啟動器

如要定義啟動器,請在 addOns.studio.flows.workflowElements 區塊中,將其新增至外掛程式資訊清單檔案 (appsscript.json)。無論是 Apps Script 或 HTTP 執行階段 (替代執行階段),都必須進行這項設定。將元素設定為 workflowTrigger,而非 workflowAction (定義步驟時使用)。詳情請參閱「Google Workspace 外掛程式的資訊清單結構」。

workflowTrigger 區塊中,指定:

  • inputs:使用者在設定資訊卡上設定的變數 (例如專案名稱、資源篩選器等)。
  • outputs:啟動器可傳回流程中下游步驟的變數。
  • onConfigFunction:顯示使用者設定介面的回呼函式名稱。
  • onManageFunction:Google 叫用的回呼函式名稱,用於處理入門訂閱方案的建立和刪除作業。

以下程式碼範例顯示事件啟動器的資訊清單定義範例:

JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Trigger App",
      "logoUrl": "https://fonts.gstatic.com/s/i/short-term/release/googlesymbols/start/default/24px.svg",
      "useLocaleFromApp": true
    },
    "studio": {
      "flows": {
        "workflowElements": [
          {
            "id": "triggerDemo",
            "state": "ACTIVE",
            "name": "Event Trigger",
            "description": "Fires when a event occurs in the app.",
            "workflowTrigger": {
              "inputs": [
                {
                  "id": "projectId",
                  "description": "The project identifier to watch.",
                  "cardinality": "SINGLE",
                  "dataType": {
                    "basicType": "STRING"
                  }
                }
              ],
              "outputs": [
                {
                  "id": "eventName",
                  "description": "The name of the triggered event.",
                  "cardinality": "SINGLE",
                  "dataType": {
                    "basicType": "STRING"
                  }
                },
                {
                  "id": "eventMessage",
                  "description": "Detailed event message description.",
                  "cardinality": "SINGLE",
                  "dataType": {
                    "basicType": "STRING"
                  }
                }
              ],
              "onConfigFunction": "onConfigTrigger",
              "onManageFunction": "onManageTrigger"
            }
          }
        ]
      }
    }
  }
}

處理入門訂閱方案的生命週期

當使用者設定並啟用含有啟動條件的流程,或流程遭到停用或刪除時,Google 會使用資訊清單中宣告的 onManageFunction 回呼函式呼叫外掛程式。

生命週期事件物件

回呼函式會收到包含動作內容的 WorkflowEventObject。首先,這包括:

  • 觸發條件建立 (event.workflow.triggerCreation):在流程發布或啟用時觸發。

    • triggerId:用來識別這個啟動器註冊執行個體的專屬 UUID 字串。

    • notifyUri:與這個入門版註冊相關聯的專屬 REST API 端點網址 (例如 https://workspacestudio.googleapis.com/v1/triggers/YOUR_TRIGGER_ID:fire)。

    • inputs:使用者從資訊卡設定的變數輸入內容。

  • 刪除觸發條件 (event.workflow.triggerDeletion):當啟動條件從流程中移除,或整個流程遭到停用或刪除時,就會觸發這項條件。

    • triggerId:要清理的訂閱項目執行個體專屬 UUID 字串。

Alternate Runtimes (HTTP API) 訂閱項目生命週期

如果是使用替代執行階段建構的外掛程式,系統會透過 HTTP POST 要求,將訂閱生命週期通知傳送至外掛程式設定的 HTTP 端點網址,並使用 onManageFunction 回呼函式指定動作名稱。酬載與 WorkflowEventObject 的 JSON 表示法相符。

如要進一步瞭解替代執行階段,請參閱「使用 HTTP 端點建構 Google Workspace 外掛程式」。

在 Apps Script 中實作生命週期回呼

下列 Apps Script 範例說明如何設定使用者介面資訊卡、使用 onManageTrigger 處理訂閱生命週期事件,以及在發生事件時將啟動要求傳回 Google。

Apps Script

/**
 * Generates and returns the user configuration card to collect inputs.
 */
function onConfigTrigger() {
  const projectInput = CardService.newTextInput()
    .setFieldName("projectId")
    .setTitle("Project ID")
    .setHint("Enter the project identifier to watch");

  const section = CardService.newCardSection()
    .setHeader("Configure Event Trigger")
    .addWidget(projectInput);

  const card = CardService.newCardBuilder()
    .addSection(section)
    .build();

  return card;
}

/**
 * Handles subscription lifecycle events sent from Google Workspace Studio.
 *
 * @param {Object} event The Workspace Studio event object.
 */
function onManageTrigger(event) {
  const triggerCreation = event.workflow.triggerCreation;
  const triggerDeletion = event.workflow.triggerDeletion;

  if (triggerCreation) {
    const triggerId = triggerCreation.triggerId;
    const notifyUri = triggerCreation.notifyUri;
    const inputs = triggerCreation.inputs;

    // Extract input values configured by the user.
    const projectId = inputs["projectId"].stringValues[0];

    // TODO: Save triggerId, notifyUri, and projectId in your database/service.
    // Your backend service listens for events related to 'projectId'
    // and calls notifyUri when those events occur.
    console.log("Trigger subscription created: " + triggerId +
                ", Notify URI: " + notifyUri +
                ", Match Project: " + projectId);

  } else if (triggerDeletion) {
    const triggerId = triggerDeletion.triggerId;

    // TODO: Remove references to triggerId from your database and stop
    // sending future event notifications to the associated notifyUri.
    console.log("Trigger subscription deleted: " + triggerId);
  }
}

/**
 * Mock function showing how your backend service fires the trigger.
 * This logic runs on your service when a watched event occurs.
 *
 * @param {string} notifyUri The stored notifyUri associated with the trigger.
 * @param {string} triggerId The stored triggerId.
 * @param {string} userAccessToken The OAuth 2.0 access token for the user
 *     (obtained using your stored refresh token).
 */
function simulateEventFire(notifyUri, triggerId, userAccessToken) {
  // A unique UUID version 4 is recommended as the requestId for idempotency.
  const requestId = Utilities.getUuid();

  const payload = {
    "name": "triggers/" + triggerId,
    "outputs": {
      "eventName": { "stringValues": ["EventOccurred"] },
      "eventMessage": { "stringValues": ["Hello from the service!"] }
    },
    "requestId": requestId
  };

  const options = {
    "method": "POST",
    "contentType": "application/json",
    "headers": {
      "Authorization": "Bearer " + userAccessToken
    },
    "payload": JSON.stringify(payload),
    "muteHttpExceptions": true
  };

  const response = UrlFetchApp.fetch(notifyUri, options);
  const responseCode = response.getResponseCode();

  if (responseCode === 200) {
    console.log("Trigger successfully fired!");
  } else if (responseCode === 404) {
    // 404 means the trigger registration is invalid or deleted.
    console.log("Trigger not found. Stop sending events for this trigger.");
    // TODO: Clean up the trigger from your backend database.
  } else if (responseCode === 429 || responseCode >= 500) {
    console.log("Temporary error (" + responseCode + "). Retry using exponential backoff.");
  } else {
    console.log("Failed to fire trigger. HTTP Code: " + responseCode + " - " + response.getContentText());
  }
}

使用 Workspace Studio API

您可以使用 Workspace Studio API (workspacestudio.googleapis.com) 以程式輔助方式,將啟動事件通知 Google。

端點位於基本路徑下方: https://workspacestudio.googleapis.com/v1

通知啟動事件

使用 triggers.fire 方法觸發啟動條件,以啟動流程的執行作業。

  • HTTP 方法POST
  • 路徑/v1/triggers/{triggerId}:fire (其中 {triggerId} 是在建立觸發條件訂閱時擷取的專屬 ID)
  • OAuth 範圍https://www.googleapis.com/auth/workspace.studio.trigger

下列程式碼範例說明如何在要求中觸發啟動器。

要求

{
  "name": "triggers/TRIGGER_ID",
  "outputs": {
    "eventName": {
      "stringValues": [
        "EventOccurred"
      ]
    },
    "eventMessage": {
      "stringValues": [
        "Hello from the service!"
      ]
    }
  },
  "log": {
    "textFormatElements": [
      {
        "text": "An event occurred in the app."
      }
    ]
  },
  "requestId": "UNIQUE_REQUEST_ID"
}
  • name (字串,必填):啟動條件的資源名稱,格式為 triggers/{triggerId}
  • outputs (地圖,選用):代表事件資料的起始輸出變數地圖。每個值都是支援型別清單的 VariableData 物件 (例如 stringValuesbooleanValuesintegerValues)。
  • log (物件,選用):顯示在 Workspace Studio 執行活動記錄中的 TextFormat 標記表示法。
  • requestId (字串,選用):最多 36 個 ASCII 字元的專屬 ID (建議使用 UUID 第 4 版),確保 API 在重試時具備等冪性。

回應

如果成功,回應會傳回空白的 JSON 物件 {}

Workspace Studio API 配額

為防止系統過載、鼓勵公平使用資源,以及保護整體 Google Workspace 效能,傳送至 workspacestudio.googleapis.com 服務的流量會受到限制。

系統會強制執行下列配額:

配額類型 配額
每項專案每分鐘 1,000 項啟動要求
每位使用者每分鐘 100 個啟動要求

配額類型如下:

  • 每項專案每分鐘:限制單一開發人員的 Google Cloud 專案觸發的啟動事件累計數量,所有執行啟動事件的使用者每分鐘最多可發出 1,000 個要求。
  • 每位使用者每分鐘:限制任何單一使用者在特定 Cloud 專案中,每分鐘累計的啟動器呼叫次數為 100 個要求。

處理時間配額錯誤

如果超出這些配額,API 會傳回 HTTP 429 Too Many Requests (或 429 Resource Exhausted) 錯誤代碼,表示超出頻率配額。

如要解決這些錯誤,程式碼應擷取例外狀況,並使用截斷的指數輪詢策略。指數輪詢會重試失敗的要求,並在每次嘗試之間逐步增加延遲時間,包括隨機抖動 (在每次疊代時重新計算隨機延遲),以防止多個用戶端同步處理並同時重試:

  1. 對 Workspace Studio API 提出要求。
  2. 如果要求失敗並顯示 429 錯誤,請等待 1 second + random_number_milliseconds 後再重試。
  3. 如果再次失敗,請等待 2 seconds + random_number_milliseconds 後再重試。
  4. 如果再次失敗,請等待 4 seconds + random_number_milliseconds 後再重試。
  5. 繼續這個迴圈,將延遲時間加倍,直到達到 maximum_backoff 門檻 (通常為 32 或 64 秒)。
  6. 達到最大延遲時間後,請使用該固定延遲時間重試,直到達到重試次數上限,然後停止並記錄錯誤。

最佳做法

設計及實作範本時,請考慮下列最佳做法:

發出單一事件,而非批次清單

請設計啟動條件,針對每個不同的事件發出個別事件 (例如更新單一記錄、發布新訊息或指派工作),而不是發出包含批次或項目清單的單一事件:

  • 與內建啟動器保持一致:在 Workspace Studio 中,內建的 Google Workspace 啟動器 (例如在 Gmail 中收到電子郵件,或使用者加入 Google Chat 空間) 會在單一事件觸發時啟動。發出單一項目事件符合這項行為,且能為所有入門套件的使用者提供一致且可預測的體驗。
  • 簡化流程設定:流程中的下游步驟通常一次處理一個項目。發出單一項目事件後,使用者就能直接對應變數,不必新增複雜的步驟來疊代陣列或剖析清單。
  • 個別處理輪詢和批次變更:如果後端服務輪詢外部 API,並在單一輪詢間隔內偵測到多個變更項目,請為每個項目觸發個別的啟動事件,而不是將這些項目綁定為一個批次事件。
  • 管理事件率和配額:為多個變更項目觸發個別事件可能會導致要求突然暴增,因此請確保服務維持在 Workspace Studio API 配額內 (例如每位使用者每分鐘 100 項要求的限制)。如果輪詢週期產生大量項目 (例如超過 100 筆變更記錄),請隨時間調整或節流事件傳送作業,避免發生 429 Too Many Requests 錯誤。

核心行為和特殊情況

整合啟動器時,開發人員必須處理特定錯誤行為和執行階段功能:

  • 不支援測試執行:Workspace Studio 不支援測試執行。
  • 等冪和防止重播:雖然並非必要,但您應在 HTTP 或 Apps Script 酬載中加入專屬 requestId (例如 UUID)。提供 requestId 可確保等冪性,因為 API 可以偵測並忽略重複通知,避免單一事件多次執行流程。
  • 已停用及重新啟用的流程:如果含有啟動條件的流程在 Workspace Studio 中停用,Google 會將 triggerDeletion 生命週期事件傳送至 onManageFunction 回呼。此外,對相關聯 FireTrigger 方法的任何呼叫都會傳回 404 Not Found 錯誤回傳代碼 (Requested entity was not found.)。您的服務應對 404 錯誤做出反應,停止傳送該啟動器執行個體 ID 的後續事件通知。

    如果使用者稍後重新啟用流程,Google 會叫用 onManageFunction 回呼,並傳送含有新 triggerIdnotifyUri 的新 triggerCreation 事件,藉此啟動新的訂閱生命週期。先前的 triggerId 已永久停用,不會重新啟用,因此您的服務不應輪詢或檢查舊版觸發程序執行個體是否已重新啟用。詳情請參閱「處理入門訂閱方案生命週期」。

  • 冪等訂閱項目刪除作業:您的 onManageFunction 回呼函式必須以冪等方式處理 Google 傳送的入門刪除要求。如果 Google 對同一個 triggerId 多次呼叫刪除掛鉤 (例如,因暫時失去連線而重試時),函式應會成功傳回。

  • 流程配額:除了 Workspace Studio API 配額外,使用者流程還須遵守額外的內部配額控制項。高頻率迴圈或過多的事件量可能會超過安全門檻,導致流程自動停用。