Cloud Scheduler 會在 HTTP 和 App Engine 要求中加入工作識別資訊和排程時間 HTTP 標頭,讓您簡化重試執行作業,並使目標處理常式冪等。Cloud Scheduler 採用「至少一次」傳遞機制,因此簡化要求可避免處理常式或下游 Google Cloud API 在逾時或網路暫時中斷時,多次處理相同的排定執行作業。
要求簡化的運作方式
在下列情況下,同一排定執行作業可能會出現重複的工作要求:
- 長時間執行的目標:目標服務的回應時間超過工作的嘗試期限 (
attemptDeadline),導致 Cloud Scheduler 逾時,並在第一次嘗試仍在執行時重試工作。如果是 HTTP 目標,attemptDeadline預設為 3 分鐘,最多可設為 30 分鐘。請根據目標的逾時時間調整attemptDeadline,如果執行時間可能超過 30 分鐘,請以非同步方式處理長時間執行的工作。 - 網路確認遺失或暫時性 Proxy 重試:目標接收並處理要求,但暫時性網路中斷或 Proxy 中斷連線,導致 Cloud Scheduler 無法收到 HTTP
2xx回應。即使將retryCount設為0,至少傳送一次的機制仍可能導致目標在暫時性傳輸失敗期間收到重複的要求。
如要讓工作處理常式具備冪等性,並簡化重試的要求,請使用 Cloud Scheduler 自動在 HTTP 和 App Engine 目標要求中加入的 HTTP 標頭:
| 標頭 | 說明 |
|---|---|
X-CloudScheduler-JobName |
projects/PROJECT_ID/locations/LOCATION_ID/jobs/JOB_ID 的簡短工作 ID (JOB_ID)。 |
X-CloudScheduler-ScheduleTime |
如果是以 對於使用替代 |
要求驗證目標端點
X-CloudScheduler-* 標頭未經驗證,可由任何呼叫端設定。請勿使用這些標頭進行驗證。請改為根據目標類型保護端點:
- HTTP 目標:設定工作來傳送 OIDC 或 OAuth 權杖,並要求在端點進行驗證。詳情請參閱「搭配 HTTP 目標使用驗證機制」。
- App Engine 目標:在
app.yaml檔案中設定login: admin,並設定 App Engine 防火牆規則,限制處理常式的存取權。
使用不區分大小寫的標頭查詢
標頭的大小寫可能因 HTTP 版本和基礎架構而異 (例如 HTTP/1.1 中的 X-Cloudscheduler-Jobname,或 HTTP/2 環境 (例如 Cloud Run) 中的小寫 x-cloudscheduler-jobname 和 x-cloudscheduler-scheduletime)。在處理常式中,一律使用不區分大小寫的標頭查詢。
區分不同專案或區域的工作 ID
Cloud Scheduler 不會自動傳送專案 ID 或區域標頭。單一處理常式端點可能會收到來自多個專案或區域的要求,這些專案或區域共用相同的 JOB_ID。在這種情況下,請在 HttpTarget.headers、AppEngineHttpTarget.headers、目標網址路徑或查詢參數中傳遞專案 ID 或區域,並將這些值納入簡化鍵。
在 HTTP 處理常式中簡化要求
在處理常式中實作要求簡化功能之前,請先完成下列設定必要條件:
- 請以
unix-cron格式設定工作排程 (例如*/5 * * * *,而非every 5 minutes),讓 Cloud Scheduler 傳送X-CloudScheduler-ScheduleTime標頭。 - 設定支援交易或不可部分完成條件式寫入的永久資料儲存庫,例如 Firestore、Spanner 或 Memorystore。在集合或資料表 (例如
expire_at欄位) 設定存留時間 (TTL) 政策,在工作重試時間範圍 (maxRetryDuration) 結束後,刪除舊的簡化記錄。Firestore TTL 會以非同步方式刪除過期記錄,通常在 24 到 72 小時內完成。如要讓重試作業在 TTL 清理前,從當機的執行個體回收執行作業,請一併儲存租約到期時間戳記 (例如lease_expires,設定為至少目標的要求逾時和attemptDeadline),並在交易中評估。
如要在 HTTP 處理常式中,只處理一次每個排定的執行作業,請完成下列步驟:
- 從傳入的要求標頭讀取
X-CloudScheduler-JobName和X-CloudScheduler-ScheduleTime,並將其雜湊為固定長度的簡化鍵 (run_id)。 - 在資料儲存庫中執行交易,檢查並宣告簡化金鑰的記錄:
- 如果記錄存在且
status為completed,請立即傳回 HTTP200 OK(或204 No Content) 狀態碼,而不執行工作邏輯,讓 Cloud Scheduler 停止重試。 - 如果記錄存在、
status為in_progress,且租約 (lease_expires) 尚未到期,請傳回可重試的錯誤狀態碼 (例如409 Conflict),讓 Cloud Scheduler 保持重試政策有效,以防執行中的嘗試失敗。請避免從 App Engine 目標傳回503 Service Unavailable,因為 App Engine 會將503視為系統錯誤,並在不計入retryCount的情況下重試要求。 - 如果記錄不存在或租約已到期,請寫入記錄,並將
status設為in_progress、不重複的嘗試 ID (attempt_id)、租約到期時間戳記 (lease_expires) 和存留時間到期時間戳記 (expire_at)。
- 如果記錄存在且
宣告記錄後,請執行工作邏輯。在交易中,請先確認記錄的
attempt_id仍與目前嘗試相符,再修改記錄:- 如果工作邏輯成功,請將
status更新為completed,並傳回 HTTP200 OK狀態碼。 - 如果工作邏輯失敗,且錯誤可以重試,請先刪除簡化記錄,再傳回
5xx狀態碼,這樣 Cloud Scheduler 就能重試執行,不必等待租約到期。
- 如果工作邏輯成功,請將
HTTP 處理常式範例
下列 Python 範例 (適用於 Cloud Run 或 Cloud Run functions) 使用 Firestore 交易和租約來宣告執行作業,並簡化重試的工作要求。
這個範例不適用於正式環境。部署前,請先查看並視需要調整:
避免向 Google Cloud API 目標重複傳送要求
Cloud Scheduler 透過 HTTP 直接叫用 Google Cloud API 端點 (*.googleapis.com) 時,目標 API 會忽略 X-CloudScheduler-JobName 和 X-CloudScheduler-ScheduleTime 標頭。舉例來說,呼叫 workflowexecutions.googleapis.com 啟動 Workflows 執行作業、呼叫 run.googleapis.com 執行 Cloud Run 工作,或呼叫 cloudbuild.googleapis.com 執行 Cloud Build 自動建構觸發條件,都會在每次重試時啟動新的執行作業。
為確保正式環境的可靠性,請在修改狀態的最下游服務中強制執行冪等性。如果只在上游層簡化要求,重試時間範圍會縮短,但如果下游要求成功,且 HTTP 回應在網路中遺失,上游呼叫端就無法判斷作業是否完成,且可能仍會重試要求。
排定 Google Cloud API 目標時,為避免重複執行,請搭配使用下列方法,確保端對端冪等性:
透過冪等 Proxy 轉送要求:不要直接從 Cloud Scheduler 呼叫
*.googleapis.com端點,而是部署自己的 Cloud Run 服務或 Cloud Run 函式 Proxy,並設定 Cloud Scheduler 叫用該 Proxy。在 Proxy 中,實作本文「簡化 HTTP 處理常式中的要求」一節所述的 Python 和 Firestore 原子交易式宣告模式。Proxy 會讀取
X-CloudScheduler-JobName和X-CloudScheduler-ScheduleTime、簡化重試的要求,並將簡化鍵做為冪等性權杖,在要求酬載中傳遞 (例如在啟動 Workflows 執行作業時,於argument欄位中傳遞)。要求對 Proxy 進行驗證 (例如使用
--no-allow-unauthenticated部署),並設定 Cloud Scheduler 工作,使用 OIDC 權杖進行驗證。在專屬服務帳戶下執行 Proxy,並僅授予最低限度的必要 Identity and Access Management (IAM) 角色 (例如目標工作流程的roles/workflows.invoker和簡化記錄的roles/datastore.user)。在下游服務中強制執行冪等性:使用冪等性權杖,在執行狀態變更步驟之前,在 Firestore 等資料儲存庫中執行原子或交易檢查。將權杖傳遞至服務叫用的任何下游 HTTP 端點或 Cloud Run 函式,讓這些目標也能簡化重試作業。如需使用 Workflows、Firestore 交易和 Cloud Run functions 的端對端範例,請參閱 Google Cloud網誌文章「使用 Workflows 時只發出一次 API 呼叫」。