O Cloud Scheduler inclui identificação de jobs e cabeçalhos HTTP de horário de programação em solicitações HTTP e do App Engine que permitem eliminar duplicação de execuções repetidas e tornar os gerenciadores de destino idempotentes. Como o Cloud Scheduler oferece entrega pelo menos uma vez, a eliminação de duplicação de solicitações impede que o gerenciador ou as APIs Google Cloud downstream processem a mesma execução programada mais de uma vez quando ocorrem tempos limite ou interrupções de rede temporárias.
Como funciona a eliminação de duplicação de solicitações
Solicitações de job duplicadas para a mesma execução programada podem ocorrer nas seguintes situações:
- Destinos de longa duração: o serviço de destino leva mais tempo para responder do que o
prazo de tentativa do job (
attemptDeadline), fazendo com que o Cloud Scheduler expire e tente novamente o job enquanto a primeira tentativa ainda está em execução. Para destinos HTTP,attemptDeadlineassume como padrão 3 minutos e pode ser configurado para até 30 minutos. AlinheattemptDeadlinecom o tempo limite do destino ou processe o trabalho de longa duração de forma assíncrona se a execução puder exceder 30 minutos. - Confirmações de rede perdidas ou novas tentativas de proxy temporárias: o destino
recebe e processa a solicitação, mas uma interrupção temporária da rede ou
uma desconexão do proxy impede que o Cloud Scheduler receba a resposta HTTP
2xx. Mesmo que você definaretryCountcomo0, a entrega pelo menos uma vez significa que um destino ainda pode receber solicitações duplicadas durante falhas de transporte temporárias.
Para tornar o gerenciador de jobs idempotente e eliminar a duplicação de solicitações repetidas, use os cabeçalhos HTTP que o Cloud Scheduler inclui automaticamente nas solicitações para destinos HTTP e do App Engine:
| Cabeçalho | Descrição |
|---|---|
X-CloudScheduler-JobName |
O identificador de job curto (JOB_ID) de
projects/PROJECT_ID/locations/LOCATION_ID/jobs/JOB_ID. |
X-CloudScheduler-ScheduleTime |
Para jobs especificados no
formato Esse cabeçalho não é garantido para jobs que usam o
formato de programação alternativo do |
Exigir autenticação no endpoint de destino
Os cabeçalhos X-CloudScheduler-* não são autenticados e podem ser definidos por qualquer
autor da chamada. Não use esses cabeçalhos para autenticação. Em vez disso, proteja o endpoint com base no tipo de destino:
- Destinos HTTP: configure o job para enviar um token OIDC ou OAuth e exigir autenticação no endpoint. Para mais informações, consulte Usar a autenticação com destinos HTTP.
- Destinos do App Engine: restrinja o acesso ao gerenciador definindo
login: adminno arquivoapp.yamle configurando regras de firewall do App Engine.
Usar pesquisas de cabeçalho que não diferenciam maiúsculas de minúsculas
As letras maiúsculas e minúsculas do cabeçalho podem variar de acordo com as versões e a infraestrutura do HTTP (por exemplo, X-Cloudscheduler-Jobname em HTTP/1.1 ou x-cloudscheduler-jobname e x-cloudscheduler-scheduletime em minúsculas em ambientes HTTP/2, como o Cloud Run). Sempre use pesquisas de cabeçalho que não diferenciam maiúsculas de minúsculas no gerenciador.
Desambiguar códigos da tarefa em projetos ou regiões
O Cloud Scheduler não envia automaticamente cabeçalhos de ID do projeto ou de região. Um único endpoint de gerenciador pode receber solicitações de vários projetos
ou regiões que compartilham o mesmo JOB_ID. Nesse caso,
transmita o ID do projeto ou a região em
HttpTarget.headers,
AppEngineHttpTarget.headers,
ou o caminho do URL de destino ou os parâmetros de consulta e inclua esses valores na sua
chave de eliminação de duplicação.
Eliminar a duplicação de solicitações em um gerenciador HTTP
Antes de implementar a eliminação de duplicação de solicitações no gerenciador, conclua os seguintes pré-requisitos de configuração:
- Configure a programação do job no formato
unix-cron(por exemplo,*/5 * * * *em vez deevery 5 minutes) para que o Cloud Scheduler envie o cabeçalhoX-CloudScheduler-ScheduleTime. - Configure um armazenamento de dados persistente que ofereça suporte a transações ou gravações condicionais atômicas, como Firestore, Spanner ou Memorystore.
Configure uma política de time to live (TTL) na
coleção ou tabela (por exemplo, no campo
expire_at) para excluir registros antigos de eliminação de duplicação após a janela de repetição do job (maxRetryDuration). O TTL do Firestore exclui registros expirados de forma assíncrona, normalmente em 24 a 72 horas. Para permitir que as novas tentativas recuperem execuções de instâncias com falha antes da limpeza do TTL, armazene também um carimbo de data/hora de expiração da concessão (comolease_expires, definido pelo menos como o tempo limite de solicitação do destino eattemptDeadline) e avalie-o em uma transação.
Para processar cada execução programada apenas uma vez no gerenciador HTTP, siga estas etapas:
- Leia
X-CloudScheduler-JobNameeX-CloudScheduler-ScheduleTimedos cabeçalhos da solicitação recebidos e faça o hash deles em uma chave de eliminação de duplicação de tamanho fixo (run_id). - Execute uma transação no seu repositório de dados para verificar e reivindicar o registro da
chave de eliminação de duplicação:
- Se o registro existir e
statusforcompleted, retorne um código de status HTTP200 OK(ou204 No Content) imediatamente sem executar a lógica do job para que o Cloud Scheduler pare de tentar novamente. - Se o registro existir,
statusforin_progresse a concessão (lease_expires) não tiver expirado, retorne um código de status de erro que permita novas tentativas, como409 Conflict, para que o Cloud Scheduler mantenha a política de novas tentativas ativa caso a tentativa em andamento falhe. Evite retornar503 Service Unavailablede destinos do App Engine, porque o App Engine trata503como um erro do sistema e repete a solicitação sem contabilizá-la emretryCount. - Se o registro não existir ou a concessão dele tiver expirado, grave o registro com
statusdefinido comoin_progress, um ID de tentativa exclusivo (attempt_id), um carimbo de data/hora de expiração da concessão (lease_expires) e um carimbo de data/hora de expiração do TTL (expire_at).
- Se o registro existir e
Depois de reivindicar o registro, execute a lógica do job. Em uma transação, verifique se o
attempt_iddo registro ainda corresponde à tentativa atual antes de modificar o registro:- Se a lógica do job for bem-sucedida, atualize
statusparacompletede retorne um código de status HTTP200 OK. - Se a lógica do job falhar com um erro que pode ser repetido, exclua o
registro de eliminação de duplicação antes de retornar um código de status
5xxpara que o Cloud Scheduler possa repetir a execução sem esperar que a concessão expire.
- Se a lógica do job for bem-sucedida, atualize
Exemplo de gerenciador HTTP
O exemplo em Python a seguir (para o Cloud Run ou Cloud Run functions) usa uma transação do Firestore com uma concessão para reivindicar execuções e eliminar a duplicação de solicitações de job repetidas.
Este exemplo não está pronto para produção. Revise e ajuste-o às suas necessidades antes da implantação:
Evitar solicitações duplicadas para destinos de API do Google Cloud
Quando o Cloud Scheduler invoca um endpoint de API do Google Cloud
(*.googleapis.com) diretamente por HTTP, a API de destino ignora os
cabeçalhos X-CloudScheduler-JobName e X-CloudScheduler-ScheduleTime. Por exemplo, chamar workflowexecutions.googleapis.com para iniciar uma execução do Workflows, run.googleapis.com para executar um job do Cloud Run ou cloudbuild.googleapis.com para executar um gatilho de build do Cloud Build inicia uma nova execução em cada tentativa.
Para confiabilidade da produção, aplique a idempotência no serviço mais downstream que modifica o estado. Eliminar a duplicação de solicitações apenas em uma camada upstream reduz a janela de repetição, mas se uma solicitação downstream for bem-sucedida e a resposta HTTP for perdida na rede, o autor da chamada upstream não poderá determinar se a operação foi concluída e ainda poderá repetir a solicitação.
Para evitar execuções duplicadas ao programar destinos da API Google Cloud , use as seguintes abordagens juntas para garantir a idempotência de ponta a ponta:
Encaminhar solicitações por um proxy idempotente: em vez de chamar o endpoint
*.googleapis.comdiretamente do Cloud Scheduler, implante seu próprio serviço do Cloud Run ou proxy de função do Cloud Run e configure o Cloud Scheduler para invocar esse proxy. No proxy, implemente o padrão de declaração transacional atômica do Python e do Firestore descrito neste documento, em Eliminar duplicação de solicitações em um gerenciador HTTP.O proxy lê
X-CloudScheduler-JobNameeX-CloudScheduler-ScheduleTime, elimina a duplicação de solicitações repetidas e transmite a chave de eliminação de duplicação como um token de idempotência no payload da solicitação (por exemplo, no campoargumentao iniciar uma execução do Workflows).Exija autenticação no proxy (por exemplo, implante com
--no-allow-unauthenticated) e configure o job do Cloud Scheduler para autenticar com um token OIDC. Execute o proxy em uma conta de serviço dedicada com apenas os papéis mínimos necessários do Identity and Access Management (IAM), comoroles/workflows.invokerno fluxo de trabalho de destino eroles/datastore.userpara os registros de eliminação de duplicação.Aplicar idempotência nos serviços downstream: use o token de idempotência para realizar uma verificação atômica ou transacional em um repositório de dados, como o Firestore, antes de executar as etapas de mudança de estado. Transmita o token para qualquer endpoint HTTP downstream ou Cloud Run functions que seu serviço invoque para que esses destinos também possam eliminar a duplicação de novas tentativas. Para um exemplo completo usando o Workflows, as transações do Firestore e o Cloud Run functions, consulte a Google Cloud postagem do blog Como fazer chamadas de API exatamente uma vez ao usar o Workflows.