使用 Cloud Tasks 將函式排入佇列


工作佇列函式可利用 Google Cloud Tasks,在主要應用程式流程之外,讓應用程式非同步執行耗時、資源密集型或有限頻寬的工作。

舉例來說,假設您要為目前託管於設有頻率限制的 API 所代管的大量圖片檔建立備份,為成為 API 的負責任消費者,請務必遵循該 API 的頻率限制。此外,這類長時間執行的工作可能會因逾時和記憶體限製而容易造成作業失敗。

如要降低這種複雜度,您可以編寫工作佇列函式來設定 scheduleTimedispatchDeadline 等基本工作選項,然後將函式交給 Cloud Tasks 中的佇列。Cloud Tasks 環境經過特別設計,能確保這類作業的有效壅塞控制和重試政策。

Cloud Functions for Firebase 3.20.1 以上版本可與 Firebase Admin SDK 10.2.0 以上版本互通,以支援工作佇列函式。

將工作佇列函式與 Firebase 搭配使用可能會導致 Cloud Tasks 的處理費用。詳情請參閱 Cloud Tasks 定價

建立工作佇列函式

如要使用工作佇列函式,請遵循以下工作流程:

  1. 使用 Cloud Functions 專用的 Firebase SDK 編寫工作佇列函式。
  2. 以 HTTP 要求觸發函式,藉此測試函式。
  3. 透過 Firebase CLI 部署函式。第一次部署工作佇列函式時,CLI 會在 Cloud Tasks 中建立工作佇列,並在原始碼中指定頻率限制和重試選項。
  4. 將工作新增到新建立的工作佇列,然後傳送參數,視需要設定執行排程。為此,您可以使用 Admin SDK 編寫程式碼,並將其部署至 Cloud Functions for Firebase。

寫入工作佇列函式

使用 onDispatch 開始編寫工作佇列函式。編寫工作佇列函式的重要部分,是設定每個佇列的重試和頻率限制設定。本頁的程式碼範例是以應用程式為基礎,此服務會備份 NASA 的 Astronomy Picture of the Day 的所有圖片:

設定工作佇列函式

工作佇列函式提供一組強大的配置設定,可讓您精確地控制工作佇列的頻率限制和重試行為:

exports.backupApod = functions
    .runWith( {secrets: ["NASA_API_KEY"]})
    .tasks.taskQueue({
      retryConfig: {
        maxAttempts: 5,
        minBackoffSeconds: 60,
      },
      rateLimits: {
        maxConcurrentDispatches: 6,
      },
    }).onDispatch(async (data) => {
  • retryConfig.maxAttempts=5:工作佇列中的每項工作最多會自動重試 5 次。這有助於減少暫時性錯誤,例如網路錯誤或依附的外部服務暫時服務中斷。
  • retryConfig.minBackoffSeconds=60:每項工作都會重試至少 60 秒 (每次重試)。每次嘗試之間可提供一個較大的緩衝區,因此不必急著用完 5 次重試嘗試。
  • rateLimits.maxConcurrentDispatch=6:一次最多只能分派 6 個工作。這有助於確保穩定串流至基礎函式的要求,並協助減少有效執行個體和冷啟動的數量。

測試工作佇列函式

Firebase 本機模擬器套件中的工作佇列函式會以簡單的 HTTP 函式公開。您可以傳送包含 JSON 資料酬載的 HTTP POST 要求,測試模擬工作函式:

 # start the Firebase Emulators
 firebase emulators:start

 # trigger the emulated task queue function
 curl \
  -X POST                                            # An HTTP POST request...
  -H "content-type: application/json" \              # ... with a JSON body
  http://localhost:$PORT/$PROJECT_ID/$REGION/$NAME \ # ... to function url
  -d '{"data": { ... some data .... }}'              # ... with JSON encoded data

部署工作佇列函式

使用 Firebase CLI 部署工作佇列函式:

$ firebase deploy --only functions:backupApod

第一次部署工作佇列函式時,CLI 會在 Cloud Tasks 中建立工作佇列,並在原始碼中指定選項 (頻率限制和重試)。

如果您在部署函式時遇到權限錯誤,請確認已將適當的 IAM 角色指派給執行部署指令的使用者。

將工作佇列函式加入佇列

您可以使用 Node.js 適用的 Firebase Admin SDK,從受信任的伺服器環境 (例如 Cloud Functions for Firebase) 將工作佇列函式排入 Cloud Tasks。如果您是第一次使用 Admin SDK,請參閱「將 Firebase 新增至伺服器」一文。

在一般流程中,Admin SDK 會建立新工作,將工作排入 Cloud Tasks,然後進行任務設定:

exports.enqueueBackupTasks = functions.https.onRequest(
async (_request, response) => {
  const queue = getFunctions().taskQueue("backupApod");
  const enqueues = [];
  for (let i = 0; i <= 10; i += 1) {
    // Enqueue each task with i*60 seconds delay. Our task queue function
    // should process ~1 task/min.
    const scheduleDelaySeconds = i * 60 
    enqueues.push(
        queue.enqueue(
          { id: `task-${i}` },
          {
            scheduleDelaySeconds,
            dispatchDeadlineSeconds: 60 * 5 // 5 minutes
          },
        ),
    );
  }
  await Promise.all(enqueues);
  response.sendStatus(200);

});
  • scheduleDelaySeconds:程式碼範例會為第 N 項任務指派第 N 分鐘的延遲時間,藉此嘗試分散工作的執行作業。這會轉譯為每分鐘約 1 項工作。請注意,如要讓 Cloud Tasks 在特定時間觸發工作,也可以使用 scheduleTime
  • dispatchDeadlineSeconds:Cloud Tasks 等待工作完成的時間長度上限。Cloud Tasks 會在佇列的重試設定後重試工作,或是到此期限結束為止。在這個範例中,佇列已設定為重試工作 5 次,如果整個程序 (包括重試嘗試) 皆超過 5 分鐘,系統將自動取消該工作。

疑難排解

開啟 Cloud Tasks 記錄功能

Cloud Tasks 中的記錄包含實用的診斷資訊,例如與工作相關聯的要求狀態。根據預設,Cloud Tasks 的記錄檔可能會因您的專案產生大量記錄檔而停用。建議您在主動開發工作佇列函式並進行偵錯時,開啟偵錯記錄。請參閱開啟記錄功能

身分與存取權管理權限

將工作加入佇列,或是 Cloud Tasks 嘗試叫用工作佇列函式時,您可能會看到 PERMISSION DENIED 錯誤。請確認您的專案具有下列 IAM 繫結:

  • 用來將工作排入 Cloud Tasks 的身分必須具備 cloudtasks.tasks.create IAM 權限。

    在本範例中,這是 App Engine 預設服務帳戶

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member=serviceAccount:${PROJECT_ID}@appspot.gserviceaccount.com \
  --role=roles/cloudtasks.enqueuer
  • 使用與 Cloud Tasks 工作相關聯的服務帳戶時,用來將工作加入佇列所用的身分需要取得權限。

    在本範例中,這是 App Engine 預設服務帳戶

如要瞭解如何將 App Engine 預設服務帳戶新增為 App Engine 預設服務帳戶的使用者,請參閱 Google Cloud IAM 說明文件

  • 用於觸發工作佇列函式的身分必須具備 cloudfunctions.functions.invoke 權限。

    在本範例中,這是 App Engine 預設服務帳戶

gcloud functions add-iam-policy-binding $FUNCTION_NAME \
  --region=us-central1 \
  --member=serviceAccount:${PROJECT_ID}@appspot.gserviceaccount.com \
  --role=roles/cloudfunctions.invoker