使用回呼和 Google 試算表暫停及繼續工作流程

Google 試算表是雲端試算表解決方案,支援即時協作,並提供資料視覺化、處理及傳達工具。

本教學課程示範如何建立及部署工作流程,以建立回呼端點 (或 Webhook)、將回呼網址儲存至 Google 試算表、暫停執行,然後等待使用者透過試算表核准,以重新啟動工作流程。進一步瞭解如何使用回呼

在 Google 雲端硬碟中建立新資料夾

在 Google 雲端硬碟中建立新資料夾。這個資料夾用於儲存試算表。設定共用資料夾的權限後,工作流程就能將資料寫入試算表。

  1. 前往 drive.google.com
  2. 依序點選「新增」「新資料夾」
  3. 輸入資料夾名稱。
  4. 點選「建立」
  5. 在新資料夾上按一下滑鼠右鍵,然後選取「共用」
  6. 新增 Compute Engine 預設服務帳戶的電子郵件地址。

    這樣服務帳戶就能存取該資料夾。將服務帳戶與工作流程建立關聯後,工作流程就能編輯資料夾中的任何檔案。進一步瞭解如何共用檔案、資料夾和雲端硬碟

  7. 選取「編輯者」角色。

  8. 取消勾選「通知共用對象」核取方塊。

  9. 按一下「共用」

使用 Google 試算表建立試算表

透過 Google 試算表建立的試算表會儲存在 Google 雲端硬碟中。根據預設,試算表會儲存到雲端硬碟的根資料夾。使用 Google 試算表 API 時,無法直接在指定資料夾中建立試算表。不過,您也可以在建立試算表後,將其移至特定資料夾,如本範例所示。詳情請參閱「使用 Google 雲端硬碟資料夾」。

  1. 前往 sheets.google.com

  2. 按一下「新增」圖示 Plus

    即可建立並開啟新的試算表。每份試算表都有專屬的spreadsheetId值,其中包含字母、數字、連字號或底線。您可以在 Google 試算表網址中找到試算表 ID:

    https://docs.google.com/spreadsheets/d/spreadsheetId/edit#gid=0

  3. 請記下這個 ID,建立工作流程時會用到。

  4. 新增欄標題,與下列範例相符:

    記錄核准的試算表範例

    請注意,系統會使用「已核准?」(G 欄) 中的值,在工作流程中啟動回呼。

  5. 將試算表移至先前建立的 Google 雲端硬碟資料夾:

    1. 在試算表中,依序選取「檔案」>「移動」
    2. 前往您建立的資料夾。
    3. 按一下 [移動]

您也可以使用 Google 試算表 API 連接器建立試算表。請注意,使用連接器時,可以從 resp 結果擷取 spreadsheetId。例如:

- create_spreadsheet:
    call: googleapis.sheets.v4.spreadsheets.create
    args:
      body:
      connector_params:
        scopes: ${driveScope}
    result: resp
- assign_sheet_id:
    assign:
      - sheetId: ${resp.spreadsheetId}

使用 Apps Script 擴充 Google 試算表功能

您可以使用 Apps Script,以程式輔助方式建立、讀取及編輯 Google 試算表。為 Google 試算表設計的指令碼大多會操控陣列,與試算表中的儲存格、列和欄互動。如要瞭解如何搭配使用 Apps Script 和 Google 試算表,請參閱自訂函式快速入門導覽課程

  1. 從 Google 試算表建立 Apps Script 專案:

    1. 開啟 Google 試算表。
    2. 依序選取「擴充功能」>「Apps Script」
    3. 在指令碼編輯器中,按一下「未命名的專案」
    4. 為專案命名,然後按一下「重新命名」

    您的指令碼現在已繫結至試算表,因此指令碼具備特殊功能,可變更使用者介面,或在試算表開啟時做出回應。

    指令碼專案代表一組 Apps Script 檔案和資源。指令碼專案中的程式碼檔案會使用 .gs 副檔名。

  2. 您可以使用 Apps Script 編寫自訂函式,並在 Google 試算表中使用,就像內建函式一樣。自訂函式是使用標準 JavaScript 建立,建立函式:

    1. 開啟 Apps Script 專案。
    2. 按一下「Editor」(編輯器) 圖示
    3. 指令碼檔案會顯示為名為 Code.gs 的專案檔案。如要編輯檔案,請選取檔案。
    4. 將指令碼編輯器中的所有程式碼,替換為下列程式碼,這段程式碼會讀取試算表中的資料,並將資料做為輸入內容傳遞至工作流程執行作業:

      function handleEdit(e) {
        var range = e.range.getA1Notation();
        var sheet = e.source;
      
        if (range.length > 1 && range[0] === 'G') {
          if (e.value == "TRUE") {
            Logger.log("Approved: TRUE");
      
            var row = range.slice(1);
            var url = sheet.getRange('E' + row).getCell(1, 1).getValue();
            var approver = sheet.getRange('F' + row).getCell(1, 1).getValue();
      
            callback(url, approver);
          }
          else {
            Logger.log("Approved: FALSE");
          }
        }
      }
      
      function callback(url, approver) {
        const headers = {
          "Authorization": "Bearer " + ScriptApp.getOAuthToken()
        };
      
        var payload = {
          'approver': approver
        };
      
        const params = {
          "method": 'POST',
          "contentType": 'application/json',
          "headers": headers,
          "payload": JSON.stringify(payload)
        };
      
      
        Logger.log("Workflow callback request to " + url);
        var response = UrlFetchApp.fetch(url, params);
        Logger.log(response);
      }
    5. 按一下「Save」(儲存) 圖示

  3. Apps Script 的可安裝觸發條件可讓指令碼專案在符合特定條件時執行指定函式,例如開啟或編輯試算表時。建立觸發條件:

    1. 開啟 Apps Script 專案。
    2. 按一下「觸發條件」
    3. 按一下「新增觸發條件」
    4. 在「Add Trigger for YOUR_PROJECT_NAME」(為 YOUR_PROJECT_NAME 新增觸發條件) 對話方塊中,設定觸發條件:
      1. 在「Choose which function to run」(選擇要執行的函式) 清單中,選取「handleEdit」
      2. 在「Choose which deployment should run」(選擇要執行的部署作業) 清單中,選取「Head」
      3. 在「選取事件來源」清單中,選取「從試算表」
      4. 在「選取事件類型」清單中,選取「編輯時」
      5. 在「失敗通知設定」清單中,選取「每天通知我」
    5. 按一下 [儲存]
    6. 如果系統提示你選擇 Google 帳戶,請選取適當的帳戶,然後按一下「允許」

      這樣一來,您的 Apps Script 專案就能查看、編輯、建立及刪除 Google 試算表,並連線至外部服務。

  4. Apps Script 專案的資訊清單檔案是 JSON 檔案,用於指定 Apps Script 順利執行指令碼所需的基本專案資訊。請注意,為保護 Apps Script 專案設定,Apps Script 編輯器預設會隱藏資訊清單檔案。編輯資訊清單檔案:

    1. 開啟 Apps Script 專案。
    2. 按一下「專案設定」
    3. 勾選「在編輯器中顯示『appsscript.json』資訊清單檔案」核取方塊。
    4. 按一下「Editor」(編輯器) 圖示
    5. 資訊清單檔案會顯示為名為 appsscript.json 的專案檔案。如要編輯檔案,請選取檔案。
    6. oauthScopes 欄位會指定字串陣列。如要設定專案使用的授權範圍,請新增包含所需範圍的陣列。例如:

      {
        "timeZone": "America/Toronto",
        "dependencies": {
        },
        "exceptionLogging": "STACKDRIVER",
        "runtimeVersion": "V8",
        "oauthScopes": [
          "https://www.googleapis.com/auth/script.external_request",
          "https://www.googleapis.com/auth/cloud-platform",
          "https://www.googleapis.com/auth/spreadsheets"
        ]
      }

      這會將明確範圍設為:

      • 連線至外部服務
      • 查看、編輯、設定及刪除您的 Google Cloud 資料,以及查看您 Google 帳戶的電子郵件地址
      • 查看、編輯、建立及刪除您的所有 Google 試算表檔案
    7. 按一下「Save」(儲存) 圖示

部署會寫入試算表並使用回呼的工作流程

部署工作流程,在透過試算表核准回呼時執行、暫停,然後繼續執行。工作流程會使用 Google Sheets API 連接器,將資料寫入 Google 試算表。

控制台

  1. 前往 Google Cloud 控制台的「Workflows」頁面:

    前往「Workflows」頁面

  2. 按一下 「建立」

  3. 輸入新工作流程的名稱:workflows-awaits-callback-sheets

  4. 在「Region」(區域) 清單中,選取「us-central1 (Iowa)」(us-central1 (愛荷華州))

  5. 在「服務帳戶」中,選取 Compute Engine 預設服務帳戶 (PROJECT_NUMBER-compute@)。

  6. 點選「下一步」

  7. 在工作流程編輯器中,輸入下列工作流程定義:

    main:
      steps:
        - init:
            assign:
            # Replace with your sheetId and make sure the service account
            # for the workflow has write permissions to the sheet
            - sheetId: "10hieAH6b-oMeIVT_AerSLNxQck14IGhgi8ign-x2x8g"
        - before_sheets_callback:
            call: sys.log
            args:
              severity: INFO
              data: ${"Execute steps here before waiting for callback from sheets"}
        - wait_for_sheets_callback:
            call: await_callback_sheets
            args:
              sheetId: ${sheetId}
            result: await_callback_result
        - after_sheets_callback:
            call: sys.log
            args:
              severity: INFO
              data: ${"Execute steps here after receiving callback from sheets"}
        - returnResult:
            return: ${await_callback_result}
    
    await_callback_sheets:
        params: [sheetId]
        steps:
            - init:
                assign:
                  - project_id: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
                  - location: ${sys.get_env("GOOGLE_CLOUD_LOCATION")}
                  - workflow_id: ${sys.get_env("GOOGLE_CLOUD_WORKFLOW_ID")}
                  - execution_id: ${sys.get_env("GOOGLE_CLOUD_WORKFLOW_EXECUTION_ID")}
            - create_callback:
                call: events.create_callback_endpoint
                args:
                  http_callback_method: POST
                result: callback_details
            - save_callback_to_sheets:
                call: googleapis.sheets.v4.spreadsheets.values.append
                args:
                    range: ${"Sheet1!A1:G1"}
                    spreadsheetId: ${sheetId}
                    valueInputOption: RAW
                    body:
                        majorDimension: "ROWS"
                        values:
                          - ["${project_id}", "${location}", "${workflow_id}", "${execution_id}", "${callback_details.url}", "", "FALSE"]
            - log_and_await_callback:
                try:
                  steps:
                    - log_await_start:
                        call: sys.log
                        args:
                          severity: INFO
                          data: ${"Started waiting for callback from sheet " + sheetId}
                    - await_callback:
                        call: events.await_callback
                        args:
                          callback: ${callback_details}
                          timeout: 3600
                        result: callback_request
                    - log_await_stop:
                        call: sys.log
                        args:
                          severity: INFO
                          data: ${"Stopped waiting for callback from sheet " + sheetId}
                except:
                    as: e
                    steps:
                        - log_error:
                            call: sys.log
                            args:
                                severity: "ERROR"
                                text: ${"Received error " + e.message}
            - check_null_await_result:
                switch:
                  - condition: ${callback_request == null}
                    return: null
            - log_await_result:
                call: sys.log
                args:
                  severity: INFO
                  data: ${"Approved by " + callback_request.http_request.body.approver}
            - return_await_result:
                return: ${callback_request.http_request.body}
  8. 請務必將預留位置 sheetId 值替換成您的 spreadsheetId

  9. 按一下 [Deploy] (部署)

gcloud

  1. 為工作流程建立原始碼檔案:

    touch workflows-awaits-callback-sheets.yaml
  2. 在文字編輯器中,將下列工作流程複製到原始碼檔案:

    main:
      steps:
        - init:
            assign:
            # Replace with your sheetId and make sure the service account
            # for the workflow has write permissions to the sheet
            - sheetId: "10hieAH6b-oMeIVT_AerSLNxQck14IGhgi8ign-x2x8g"
        - before_sheets_callback:
            call: sys.log
            args:
              severity: INFO
              data: ${"Execute steps here before waiting for callback from sheets"}
        - wait_for_sheets_callback:
            call: await_callback_sheets
            args:
              sheetId: ${sheetId}
            result: await_callback_result
        - after_sheets_callback:
            call: sys.log
            args:
              severity: INFO
              data: ${"Execute steps here after receiving callback from sheets"}
        - returnResult:
            return: ${await_callback_result}
    
    await_callback_sheets:
        params: [sheetId]
        steps:
            - init:
                assign:
                  - project_id: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
                  - location: ${sys.get_env("GOOGLE_CLOUD_LOCATION")}
                  - workflow_id: ${sys.get_env("GOOGLE_CLOUD_WORKFLOW_ID")}
                  - execution_id: ${sys.get_env("GOOGLE_CLOUD_WORKFLOW_EXECUTION_ID")}
            - create_callback:
                call: events.create_callback_endpoint
                args:
                  http_callback_method: POST
                result: callback_details
            - save_callback_to_sheets:
                call: googleapis.sheets.v4.spreadsheets.values.append
                args:
                    range: ${"Sheet1!A1:G1"}
                    spreadsheetId: ${sheetId}
                    valueInputOption: RAW
                    body:
                        majorDimension: "ROWS"
                        values:
                          - ["${project_id}", "${location}", "${workflow_id}", "${execution_id}", "${callback_details.url}", "", "FALSE"]
            - log_and_await_callback:
                try:
                  steps:
                    - log_await_start:
                        call: sys.log
                        args:
                          severity: INFO
                          data: ${"Started waiting for callback from sheet " + sheetId}
                    - await_callback:
                        call: events.await_callback
                        args:
                          callback: ${callback_details}
                          timeout: 3600
                        result: callback_request
                    - log_await_stop:
                        call: sys.log
                        args:
                          severity: INFO
                          data: ${"Stopped waiting for callback from sheet " + sheetId}
                except:
                    as: e
                    steps:
                        - log_error:
                            call: sys.log
                            args:
                                severity: "ERROR"
                                text: ${"Received error " + e.message}
            - check_null_await_result:
                switch:
                  - condition: ${callback_request == null}
                    return: null
            - log_await_result:
                call: sys.log
                args:
                  severity: INFO
                  data: ${"Approved by " + callback_request.http_request.body.approver}
            - return_await_result:
                return: ${callback_request.http_request.body}
  3. 請務必將預留位置 sheetId 值替換成您的 spreadsheetId

  4. 輸入下列指令來部署工作流程:

    gcloud workflows deploy workflows-awaits-callback-sheets \
        --source=workflows-awaits-callback-sheets.yaml \
        --location=us-central1 \
        --service-account=PROJECT_NUMBER-compute@

    PROJECT_NUMBER 替換為專案編號。 Google Cloud您可以透過下列方式取得專案編號:

    gcloud projects describe PROJECT_ID

測試端對端流程

執行工作流程,測試端對端流程。執行工作流程時,系統會執行與該工作流程相關聯的目前工作流程定義。

控制台

  1. 前往 Google Cloud 控制台的「Workflows」頁面:

    前往「Workflows」頁面

  2. 在「Workflows」頁面中,選取「workflows-awaits-callback-sheets」工作流程,前往詳細資料頁面。

  3. 在「工作流程詳細資料」頁面中,按一下 「執行」

  4. 再次按一下「執行」

    工作流程會開始執行,執行狀態應為「執行中」。記錄檔也會指出工作流程已暫停並等待:

    Execute steps here before waiting for callback from sheets
    ...
    Started waiting for callback from sheet 1JlNFFnqs760M_KDqeeeDc_qtrABZDxoalyCmRE39dpM
  5. 確認工作流程已將回呼詳細資料寫入試算表中的資料列。

    舉例來說,您應該會在「執行 ID」欄中看到工作流程執行 ID、「回呼網址」欄中看到回呼端點,以及「已核准?」欄中看到「FALSE」

  6. 在試算表中,將 FALSE 變更為 TRUE

    一兩分鐘後,執行作業應會繼續,然後以「Succeeded」的執行狀態完成。

gcloud

  1. 開啟終端機。

  2. 執行工作流程:

      gcloud workflows run workflows-awaits-callback-sheets

    工作流程會啟動,輸出內容應會指出工作流程已暫停並等待:

      Waiting for execution [a8361789-90e0-467f-8bd7-ea1c81977820] to complete...working.

  3. 確認工作流程已將回呼詳細資料寫入試算表中的資料列。

    舉例來說,您應該會在「執行 ID」欄中看到工作流程執行 ID、「回呼網址」欄中看到回呼端點,以及「已核准?」欄中看到「FALSE」

  4. 在試算表中,將 FALSE 變更為 TRUE

    一兩分鐘後,執行作業應會繼續,然後以 SUCCEEDED 的執行狀態完成。