Cloud Scheduler include intestazioni HTTP di identificazione del job e di pianificazione nelle richieste HTTP e App Engine che consentono di deduplicare le esecuzioni ritentate e di rendere idempotenti i gestori di destinazione. Poiché Cloud Scheduler fornisce la distribuzione at-least-once, la deduplicazione delle richieste impedisce al gestore o alle API Google Cloud downstream di elaborare la stessa esecuzione pianificata più di una volta quando si verificano timeout o interruzioni di rete temporanee.
Come funziona la deduplicazione delle richieste
Le richieste di job duplicate per la stessa esecuzione pianificata possono verificarsi nelle seguenti situazioni:
- Target a lunga esecuzione: il servizio di destinazione impiega più tempo a rispondere rispetto alla scadenza del tentativo del job (
attemptDeadline), causando il timeout di Cloud Scheduler e il nuovo tentativo del job mentre il primo tentativo è ancora in esecuzione. Per i target HTTP, il valore predefinito diattemptDeadlineè 3 minuti e può essere configurato fino a 30 minuti. AllineaattemptDeadlineal timeout della destinazione o elabora il lavoro a lunga esecuzione in modo asincrono se l'esecuzione può superare i 30 minuti. - Conferme di rete perse o nuovi tentativi di proxy temporanei: la destinazione riceve ed elabora la richiesta, ma un'interruzione di rete temporanea o una disconnessione del proxy impedisce a Cloud Scheduler di ricevere la risposta HTTP
2xx. Anche se impostiretryCountsu0, la distribuzione di tipo "at-least-once" (almeno una volta) significa che un target può comunque ricevere richieste duplicate durante errori di trasporto temporanei.
Per rendere idempotente il gestore dei job e deduplicare le richieste ritentate, utilizza le intestazioni HTTP che Cloud Scheduler include automaticamente nelle richieste ai target HTTP e App Engine:
| Intestazione | Descrizione |
|---|---|
X-CloudScheduler-JobName |
L'identificatore breve del job (JOB_ID) da projects/PROJECT_ID/locations/LOCATION_ID/jobs/JOB_ID. |
X-CloudScheduler-ScheduleTime |
Per i job specificati nel formato Questa intestazione non è garantita per i job che utilizzano il
formato di pianificazione |
Richiedi l'autenticazione sull'endpoint di destinazione
Le intestazioni X-CloudScheduler-* non sono autenticate e possono essere impostate da qualsiasi chiamante. Non utilizzare queste intestazioni per l'autenticazione. Proteggi invece l'endpoint in base al tipo di target:
- Target HTTP: configura il job in modo che invii un token OIDC o OAuth e richieda l'autenticazione sul tuo endpoint. Per saperne di più, consulta Utilizza l'autenticazione con target HTTP.
- Target di App Engine: limita l'accesso al gestore impostando
login: adminnel fileapp.yamle configurando regole firewall di App Engine.
Utilizza ricerche di intestazioni senza distinzione tra maiuscole e minuscole
L'uso delle maiuscole nelle intestazioni può variare a seconda delle versioni e dell'infrastruttura HTTP (ad esempio, X-Cloudscheduler-Jobname in HTTP/1.1 o x-cloudscheduler-jobname e x-cloudscheduler-scheduletime in minuscolo negli ambienti HTTP/2 come Cloud Run). Utilizza sempre ricerche di intestazioni senza distinzione tra maiuscole e minuscole nel gestore.
Elimina l'ambiguità degli ID job tra progetti o regioni
Cloud Scheduler non invia automaticamente le intestazioni dell'ID progetto o della regione. Un singolo endpoint del gestore potrebbe ricevere richieste da più progetti o regioni che condividono lo stesso JOB_ID. In questo caso,
passa l'ID progetto o la regione in
HttpTarget.headers,
AppEngineHttpTarget.headers,
o i parametri di ricerca o il percorso dell'URL di destinazione e includi questi valori nella
chiave di deduplicazione.
Deduplica le richieste in un gestore HTTP
Prima di implementare la deduplicazione delle richieste nel gestore, completa i seguenti prerequisiti di configurazione:
- Configura la pianificazione del job nel formato
unix-cron(ad esempio,*/5 * * * *anzichéevery 5 minutes) in modo che Cloud Scheduler invii l'intestazioneX-CloudScheduler-ScheduleTime. - Configura un datastore permanente che supporti le transazioni o le scritture condizionali atomiche, come Firestore, Spanner o Memorystore.
Configura una policy di durata (TTL) sulla raccolta o sulla tabella (ad esempio sul campo
expire_at) per eliminare i record di deduplicazione precedenti dopo la finestra di ripetizione del job (maxRetryDuration). Il TTL di Firestore elimina i record scaduti in modo asincrono, in genere entro 24-72 ore. Per consentire ai nuovi tentativi di recuperare le esecuzioni dalle istanze che hanno subito un arresto anomalo prima della pulizia del TTL, memorizza anche un timestamp di scadenza del lease (ad esempiolease_expires, impostato almeno sul timeout della richiesta della destinazione e suattemptDeadline) e valutalo in una transazione.
Per elaborare ogni esecuzione pianificata una sola volta nel gestore HTTP, completa i seguenti passaggi:
- Leggi
X-CloudScheduler-JobNameeX-CloudScheduler-ScheduleTimedalle intestazioni della richiesta in entrata ed esegui l'hashing in una chiave di deduplicazione di lunghezza fissa (run_id). - Esegui una transazione nel datastore per controllare e rivendicare il record per la chiave di deduplicazione:
- Se il record esiste e
statusècompleted, restituisci immediatamente un codice di stato HTTP200 OK(o204 No Content) senza eseguire la logica del job, in modo che Cloud Scheduler interrompa i nuovi tentativi. - Se il record esiste,
statusèin_progresse il lease (lease_expires) non è scaduto, restituisci un codice di stato di errore ripetibile come409 Conflictin modo che Cloud Scheduler mantenga attiva la policy di ripetizione nel caso in cui il tentativo in corso non vada a buon fine. Evita di restituire503 Service Unavailabledai target App Engine, perché App Engine tratta503come un errore di sistema e riprova la richiesta senza conteggiarla inretryCount. - Se il record non esiste o il suo lease è scaduto, scrivi il record con
statusimpostato suin_progress, un ID tentativo univoco (attempt_id), un timestamp di scadenza del lease (lease_expires) e un timestamp di scadenza del TTL (expire_at).
- Se il record esiste e
Dopo aver rivendicato il record, esegui la logica del job. In una transazione, verifica che il valore
attempt_iddel record corrisponda ancora al tentativo corrente prima di modificare il record:- Se la logica del job ha esito positivo, aggiorna
statusincompletede restituisci un codice di stato HTTP200 OK. - Se la logica del job non va a buon fine con un errore per cui puoi riprovare, elimina il record di deduplicazione prima di restituire un codice di stato
5xxin modo che Cloud Scheduler possa riprovare l'esecuzione senza attendere la scadenza del lease.
- Se la logica del job ha esito positivo, aggiorna
Esempio di gestore HTTP
Il seguente esempio Python (per Cloud Run o Cloud Run Functions) utilizza una transazione Firestore con un lease per rivendicare le esecuzioni e deduplicare le richieste di job ritentate.
Questo esempio non è pronto per la produzione. Esaminalo e adattalo alle tue esigenze prima del deployment:
Evita richieste duplicate alle destinazioni API Google Cloud
Quando Cloud Scheduler richiama un endpoint API Google Cloud
(*.googleapis.com) direttamente tramite HTTP, l'API di destinazione ignora le
intestazioni X-CloudScheduler-JobName e X-CloudScheduler-ScheduleTime. Ad esempio, la chiamata di workflowexecutions.googleapis.com per avviare un'esecuzione di Workflows, di run.googleapis.com per eseguire un job Cloud Run o di cloudbuild.googleapis.com per eseguire un trigger di Cloud Build avvia una nuova esecuzione a ogni tentativo di ripetizione.
Per l'affidabilità della produzione, applica l'idempotenza nel servizio più a valle che modifica lo stato. La deduplicazione delle richieste solo a un livello upstream restringe la finestra di nuovi tentativi, ma se una richiesta downstream va a buon fine e la risposta HTTP viene persa sulla rete, il chiamante upstream non può determinare se l'operazione è stata completata e potrebbe comunque riprovare la richiesta.
Per evitare esecuzioni duplicate durante la pianificazione di target API Google Cloud , utilizza i seguenti approcci insieme per l'idempotenza end-to-end:
Instrada le richieste tramite un proxy idempotente: anziché chiamare l'endpoint
*.googleapis.comdirettamente da Cloud Scheduler, esegui il deployment del tuo servizio Cloud Run o del proxy Cloud Run Functions e configura Cloud Scheduler per richiamare quel proxy. Nel proxy, implementa il pattern di rivendicazione transazionale atomica di Python e Firestore descritto in questo documento, in Deduplica le richieste in un gestore HTTP.Il proxy legge
X-CloudScheduler-JobNameeX-CloudScheduler-ScheduleTime, deduplica le richieste ripetute e passa la chiave di deduplicazione come token di idempotenza nel payload della richiesta (ad esempio nel campoargumentquando avvia un'esecuzione di Workflows).Richiedi l'autenticazione sul proxy (ad esempio, esegui il deployment con
--no-allow-unauthenticated) e configura il job Cloud Scheduler per eseguire l'autenticazione con un token OIDC. Esegui il proxy in un account di servizio dedicato con solo i ruoli Identity and Access Management (IAM) minimi richiesti (ad esempioroles/workflows.invokernel workflow di destinazione eroles/datastore.userper i record di deduplicazione).Applica l'idempotenza nei servizi downstream: utilizza il token di idempotenza per eseguire un controllo atomico o transazionale in un datastore come Firestore prima di eseguire i passaggi di modifica dello stato. Passa il token a qualsiasi endpoint HTTP downstream o Cloud Run Functions richiamato dal tuo servizio, in modo che anche questi target possano deduplicare i nuovi tentativi. Per un esempio end-to-end che utilizza Workflows, le transazioni Firestore e Cloud Run Functions, consulta il blog post di Google Cloud, Effettuare chiamate API esattamente una volta quando utilizzi Workflows.