Cloud Scheduler enthält Jobidentifikations- und Zeitplan-HTTP-Header für HTTP- und App Engine-Anfragen, mit denen Sie wiederholte Ausführungen deduplizieren und Ihre Ziel-Handler idempotent machen können. Da Cloud Scheduler eine At-Least-Once-Zustellung bietet, wird durch die Deduplizierung von Anfragen verhindert, dass Ihr Handler oder nachgelagerte Google Cloud -APIs dieselbe geplante Ausführung mehr als einmal verarbeiten, wenn Zeitüberschreitungen oder vorübergehende Netzwerkunterbrechungen auftreten.
Funktionsweise der Deduplizierung von Anfragen
Doppelte Jobanfragen für dieselbe geplante Ausführung können in den folgenden Situationen auftreten:
- Ziele mit langer Laufzeit: Der Zieldienst benötigt länger für die Antwort als die Versuchsfrist (
attemptDeadline) des Jobs. Dies führt zu einer Zeitüberschreitung in Cloud Scheduler und der Job wird wiederholt, während der erste Versuch noch läuft. Bei HTTP-Zielen beträgt der Standardwert fürattemptDeadline3 Minuten. Er kann auf bis zu 30 Minuten konfiguriert werden. Richten SieattemptDeadlineam Zeitlimit Ihres Ziels aus oder verarbeiten Sie lang andauernde Aufgaben asynchron, wenn die Ausführung länger als 30 Minuten dauern kann. - Verlorene Netzwerkbestätigungen oder vorübergehende Proxy-Wiederholungen: Das Ziel empfängt und verarbeitet die Anfrage, aber eine vorübergehende Netzwerkunterbrechung oder Proxy-Trennung verhindert, dass Cloud Scheduler die HTTP-
2xx-Antwort empfängt. Auch wenn SieretryCountauf0setzen, bedeutet die „Mindestens einmal“-Zustellung, dass ein Ziel bei vorübergehenden Transportfehlern weiterhin doppelte Anfragen erhalten kann.
Wenn Sie Ihren Job-Handler idempotent machen und wiederholte Anfragen deduplizieren möchten, verwenden Sie die HTTP-Header, die Cloud Scheduler automatisch in Anfragen an HTTP- und App Engine-Ziele einfügt:
| Header | Beschreibung |
|---|---|
X-CloudScheduler-JobName |
Die kurze Job-ID (JOB_ID) aus projects/PROJECT_ID/locations/LOCATION_ID/jobs/JOB_ID. |
X-CloudScheduler-ScheduleTime |
Für Jobs im Dieser Header ist nicht für Jobs garantiert, die das alternative |
Authentifizierung am Zielendpunkt anfordern
Die X-CloudScheduler-*-Header sind nicht authentifiziert und können von jedem Aufrufer festgelegt werden. Verwenden Sie diese Header nicht für die Authentifizierung. Sichern Sie stattdessen Ihren Endpunkt basierend auf dem Zieltyp:
- HTTP-Ziele: Konfigurieren Sie den Job so, dass ein OIDC- oder OAuth-Token gesendet wird und eine Authentifizierung am Endpunkt erforderlich ist. Weitere Informationen finden Sie unter Authentifizierung mit HTTP-Zielen verwenden.
- App Engine-Ziele: Schränken Sie den Zugriff auf den Handler ein, indem Sie
login: adminin der Dateiapp.yamlfestlegen und App Engine-Firewallregeln konfigurieren.
Header-Suchvorgänge ohne Berücksichtigung der Groß-/Kleinschreibung verwenden
Die Groß-/Kleinschreibung von Headern kann je nach HTTP-Version und Infrastruktur variieren (z. B. X-Cloudscheduler-Jobname in HTTP/1.1 oder Kleinbuchstaben x-cloudscheduler-jobname und x-cloudscheduler-scheduletime in HTTP/2-Umgebungen wie Cloud Run). Verwenden Sie in Ihrem Handler immer Header-Lookups, bei denen die Groß-/Kleinschreibung nicht berücksichtigt wird.
Job-IDs über Projekte oder Regionen hinweg eindeutig machen
Cloud Scheduler sendet nicht automatisch Projekt-ID- oder Regions-Header. Ein einzelner Handler-Endpunkt kann Anfragen von mehreren Projekten oder Regionen empfangen, die dieselbe JOB_ID verwenden. Übergeben Sie in diesem Fall die Projekt-ID oder Region in HttpTarget.headers, AppEngineHttpTarget.headers oder den Ziel-URL-Pfad oder die Suchparameter und fügen Sie diese Werte in Ihren Deduplizierungsschlüssel ein.
Anfragen in einem HTTP-Handler deduplizieren
Bevor Sie die Deduplizierung von Anfragen in Ihrem Handler implementieren, müssen Sie die folgenden Voraussetzungen erfüllen:
- Konfigurieren Sie den Zeitplan Ihres Jobs im
unix-cron-Format (z. B.*/5 * * * *stattevery 5 minutes), damit Cloud Scheduler den HeaderX-CloudScheduler-ScheduleTimesendet. - Richten Sie einen nichtflüchtigen Datenspeicher ein, der Transaktionen oder atomare bedingte Schreibvorgänge unterstützt, z. B. Firestore, Spanner oder Memorystore.
Konfigurieren Sie eine TTL-Richtlinie (Time-to-Live) für die Sammlung oder Tabelle (z. B. für das Feld
expire_at), um alte Deduplizierungsdatensätze nach dem Wiederholungsfenster des Jobs (maxRetryDuration) zu löschen. Die Firestore-TTL löscht abgelaufene Datensätze asynchron, in der Regel innerhalb von 24–72 Stunden. Damit Wiederholungsversuche Ausführungen von abgestürzten Instanzen vor der TTL-Bereinigung zurückfordern können, speichern Sie auch einen Zeitstempel für den Ablauf der Lease (z. B.lease_expires, der mindestens auf das Zeitlimit für Anfragen Ihres Ziels undattemptDeadlinefestgelegt ist) und werten Sie ihn in einer Transaktion aus.
Führen Sie die folgenden Schritte aus, um jede geplante Ausführung nur einmal in Ihrem HTTP-Handler zu verarbeiten:
X-CloudScheduler-JobNameundX-CloudScheduler-ScheduleTimeaus den eingehenden Anfrageheadern lesen und in einen Deduplizierungsschlüssel mit fester Länge (run_id) hashen.- Führen Sie eine Transaktion in Ihrem Datenspeicher aus, um den Datensatz für den Deduplizierungsschlüssel zu prüfen und zu beanspruchen:
- Wenn der Eintrag vorhanden ist und
statusden Wertcompletedhat, geben Sie sofort einen HTTP-Statuscode200 OK(oder204 No Content) zurück, ohne die Joblogik auszuführen, damit Cloud Scheduler keine weiteren Versuche unternimmt. - Wenn der Eintrag vorhanden ist,
statusden Wertin_progresshat und die Lease (lease_expires) nicht abgelaufen ist, geben Sie einen wiederholbaren Fehlerstatuscode wie409 Conflictzurück, damit Cloud Scheduler seine Wiederholungsrichtlinie aktiv hält, falls der laufende Versuch fehlschlägt. Vermeiden Sie die Rückgabe von503 Service Unavailablevon App Engine-Zielen, da App Engine503als Systemfehler behandelt und die Anfrage wiederholt, ohne sie aufretryCountanzurechnen. - Wenn der Eintrag nicht vorhanden ist oder die Freigabe abgelaufen ist, schreiben Sie den Eintrag mit
statusaufin_progress, einer eindeutigen Versuchs-ID (attempt_id), einem Zeitstempel für den Ablauf der Freigabe (lease_expires) und einem Zeitstempel für den Ablauf der TTL (expire_at).
- Wenn der Eintrag vorhanden ist und
Führen Sie nach dem Beanspruchen des Datensatzes die Joblogik aus. Prüfen Sie in einer Transaktion, ob der
attempt_iddes Datensatzes noch mit dem aktuellen Versuch übereinstimmt, bevor Sie den Datensatz ändern:- Wenn die Joblogik erfolgreich ist, aktualisieren Sie
statusaufcompletedund geben Sie den HTTP-Statuscode200 OKzurück. - Wenn die Joblogik mit einem Fehler fehlschlägt, den Sie wiederholen können, löschen Sie den Deduplizierungseintrag, bevor Sie den Statuscode
5xxzurückgeben, damit Cloud Scheduler die Ausführung wiederholen kann, ohne auf den Ablauf der Lease zu warten.
- Wenn die Joblogik erfolgreich ist, aktualisieren Sie
Beispiel für einen HTTP-Handler
Im folgenden Python-Beispiel (für Cloud Run oder Cloud Run Functions) wird eine Firestore-Transaktion mit einer Lease verwendet, um Ausführungen zu beanspruchen und wiederholte Jobanfragen zu deduplizieren.
Dieses Beispiel ist nicht produktionsreif. Prüfen Sie die Datei und passen Sie sie vor der Bereitstellung an Ihre Anforderungen an:
Doppelte Anfragen an Google Cloud API-Ziele verhindern
Wenn Cloud Scheduler einen Google Cloud -API-Endpunkt (*.googleapis.com) direkt über HTTP aufruft, ignoriert die Ziel-API die Header X-CloudScheduler-JobName und X-CloudScheduler-ScheduleTime. Wenn Sie beispielsweise workflowexecutions.googleapis.com aufrufen, um eine Workflow-Ausführung zu starten, run.googleapis.com, um einen Cloud Run-Job auszuführen, oder cloudbuild.googleapis.com, um einen Cloud Build-Trigger auszuführen, wird bei jedem Wiederholungsversuch eine neue Ausführung gestartet.
Erzwingen Sie für die Produktionszuverlässigkeit die Idempotenz im am weitesten nachgelagerten Dienst, der den Status ändert. Wenn Anfragen nur auf einer Upstream-Ebene dedupliziert werden, wird das Wiederholungsfenster verkleinert. Wenn jedoch eine Downstream-Anfrage erfolgreich ist und die HTTP-Antwort über das Netzwerk verloren geht, kann der Upstream-Aufrufer nicht feststellen, ob der Vorgang abgeschlossen wurde, und die Anfrage möglicherweise trotzdem wiederholen.
Wenn Sie doppelte Ausführungen beim Planen von Google Cloud API-Zielen verhindern möchten, verwenden Sie die folgenden Ansätze zusammen, um eine End-to-End-Idempotenz zu erreichen:
Anfragen über einen idempotenten Proxy weiterleiten: Anstatt den
*.googleapis.com-Endpunkt direkt über Cloud Scheduler aufzurufen, stellen Sie Ihren eigenen Cloud Run-Dienst oder Cloud Run Functions-Proxy bereit und konfigurieren Sie Cloud Scheduler so, dass dieser Proxy aufgerufen wird. Implementieren Sie im Proxy das in diesem Dokument unter Anfragen in einem HTTP-Handler deduplizieren beschriebene atomare Transaktionsanspruchsmuster für Python und Firestore.Der Proxy liest
X-CloudScheduler-JobNameundX-CloudScheduler-ScheduleTime, dedupliziert wiederholte Anfragen und übergibt den Deduplizierungsschlüssel als Idempotenztoken in der Nutzlast der Anfrage (z. B. im Feldargumentbeim Starten einer Workflows-Ausführung).Erfordern Sie eine Authentifizierung auf dem Proxy (z. B. Bereitstellung mit
--no-allow-unauthenticated) und konfigurieren Sie den Cloud Scheduler-Job so, dass er sich mit einem OIDC-Token authentifiziert. Führen Sie den Proxy unter einem dedizierten Dienstkonto mit nur den mindestens erforderlichen IAM-Rollen (Identity and Access Management) aus (z. B.roles/workflows.invokerfür den Zielworkflow undroles/datastore.userfür die Deduplizierungseinträge).Idempotenz in den Downstream-Diensten erzwingen: Verwenden Sie das Idempotenztoken, um eine atomare oder transaktionale Prüfung in einem Datenspeicher wie Firestore durchzuführen, bevor Sie zustandsändernde Schritte ausführen. Übergeben Sie das Token an alle nachgelagerten HTTP-Endpunkte oder Cloud Run-Funktionen, die Ihr Dienst aufruft, damit diese Ziele auch Wiederholungsversuche deduplizieren können. Ein End-to-End-Beispiel mit Workflows, Firestore-Transaktionen und Cloud Run Functions finden Sie im Google CloudBlogpost API-Aufrufe genau einmal ausführen, wenn Workflows verwendet werden.