Jobs em segundo plano

Boa parte do Studio roda em um agendamento, e não em resposta a uma requisição de usuário: workflows agendados, todos os triggers de polling, syncs de conectores, o outbox, a drenagem de dados e a retenção. Tudo isso é movido por endpoints HTTP que algo externo precisa chamar em intervalos regulares.

Os dois modelos de implantação já incluem um agendador e o habilitam por padrão: o Kubernetes como CronJobs, o Docker Compose como um serviço cron. Os dois autenticam com o CRON_SECRET e usam os mesmos agendamentos.

Autenticação

Todos os endpoints são protegidos pelo CRON_SECRET e o esperam como bearer token:

curl -f -s -S --max-time 60 \
  -H "Authorization: Bearer $CRON_SECRET" \
  https://studio.yourdomain.com/api/schedules/execute

Gere-o como os outros secrets:

openssl rand -hex 32

O CRON_SECRET é obrigatório sempre que os jobs em segundo plano estiverem habilitados — o que é o padrão do Helm chart. O chart se recusa a renderizar sem ele. Se não estiver definido, os endpoints rejeitam todas as chamadas e todo o trabalho agendado para silenciosamente.

Aponte o cron para um endereço interno quando possível (o Service dentro do cluster, ou localhost em um nó único). Esses endpoints não deveriam ser acessíveis pela internet; se forem, o CRON_SECRET é a única coisa que os protege.

Os jobs

JobEndpointAgendamentoMovimenta
Execução de agendamentos/api/schedules/execute*/1 * * * *Workflows agendados
Polling do Gmail/api/webhooks/poll/gmail*/1 * * * *Trigger do Gmail
Polling do Outlook/api/webhooks/poll/outlook*/1 * * * *Trigger do Outlook
Polling de IMAP/api/webhooks/poll/imap*/1 * * * *Trigger de IMAP
Polling de RSS/api/webhooks/poll/rss*/1 * * * *Trigger de RSS
Polling do Google Sheets/api/webhooks/poll/google-sheets*/1 * * * *Trigger do Sheets
Polling do Google Drive/api/webhooks/poll/google-drive*/1 * * * *Trigger do Drive
Polling do Google Calendar/api/webhooks/poll/google-calendar*/1 * * * *Trigger do Calendar
Polling do HubSpot/api/webhooks/poll/hubspot*/1 * * * *Trigger do HubSpot
Pausa/retomada por tempo/api/resume/poll*/1 * * * *Workflows pausados por tempo
Processamento do outbox/api/webhooks/outbox/process*/1 * * * *Retentativas do outbox transacional para cobrança, participação, emissão enterprise e efeitos colaterais do deploy de workflows
Sync de conectores/api/knowledge/connectors/sync*/5 * * * *Syncs dos conectores da base de conhecimento
Polling de eventos de workspace/api/workspace-events/poll*/15 * * * *Triggers de eventos de workspace
Drenagem de dados/api/cron/run-data-drains0 * * * *Drenagem de dados enterprise
Renovação de assinaturas/api/cron/renew-subscriptions0 */12 * * *Renova as assinaturas de chat do Microsoft Teams (o Graph as limita a cerca de 3 dias)
Reconciliação de assentos de cobrança/api/cron/reconcile-billing-seats0 * * * *Só cobrança — pode ser desativado com segurança na auto-hospedagem
Reconciliação de acesso ao inbox/api/cron/reconcile-inbox-entitlement0 3 * * *Reconciliação de acesso ao inbox
Limpeza de imagens de sandbox/api/cron/cleanup-sandbox-images30 4 * * *Recupera espaço das imagens de sandbox

A renovação de assinaturas cobre os triggers de chat do Microsoft Teams, cujas assinaturas no Microsoft Graph têm limite fixo de cerca de três dias. Sem ela, os triggers do Teams funcionam por alguns dias e depois param sem aviso. Os triggers de Gmail, Outlook, Drive, Calendar e Sheets funcionam por polling — eles dependem dos jobs de polling por minuto acima, não deste.

Kubernetes

Habilitado por padrão. Não há nada a fazer além de definir o CRON_SECRET.

cronjobs:
  enabled: true

Cada job roda um pequeno pod curlimages/curl que chama o Service do app dentro do cluster (não o ingress), com concurrencyPolicy: Forbid para que uma execução lenta nunca se sobreponha a si mesma, e até três retentativas.

Desative individualmente os jobs de que você não precisa — a reconciliação de cobrança é o caso mais óbvio em uma instalação auto-hospedada:

cronjobs:
  jobs:
    reconcileBillingSeats:
      enabled: false

Verifique se estão rodando:

kubectl get cronjobs -n studio
kubectl get jobs -n studio --sort-by=.metadata.creationTimestamp | tail
kubectl logs -n studio job/<job-name>

Um CronJob cujo LAST SCHEDULE está desatualizado, ou cujos jobs estão falhando, significa que o recurso correspondente está morto. Crie um alerta para isso — veja Observabilidade.

Docker Compose

O serviço cron roda os mesmos jobs nos mesmos agendamentos, então não há nada a configurar além do CRON_SECRET:

CRON_SECRET=$(openssl rand -hex 32)

Sem ele, o serviço cron registra no log exatamente o que definir — inclusive um valor recém-gerado — e encerra, deixando o resto da stack em pé. Os agendamentos ficam em docker/crontab e espelham um a um o cronjobs.jobs de helm/studio/values.yaml.

Está atualizando uma implantação criada antes de o agendador existir? Seu .env não tem CRON_SECRET, então a stack sobe como antes e o cron encerra com instruções. Adicione o valor e rode up -d de novo para ligar os jobs em segundo plano.

O serviço roda o supercronic em vez da imagem do app: ele registra a saída de cada job no log do contêiner, repassa o SIGTERM para que docker compose stop seja gracioso, e não inicia uma iteração enquanto a anterior ainda está em execução.

docker compose -f docker-compose.prod.yml logs -f cron

Uma linha de log saudável se parece com isto:

level=info msg=starting iteration=0 job.schedule="*/1 * * * *"
level=info msg="job succeeded" iteration=0

Para descartar um job de que você não precisa, comente a linha dele em docker/crontab e reinicie o serviço.

Verificando

Crie um workflow com um trigger Schedule definido para cada minuto, faça o deploy e acompanhe a visão Logs. Uma execução deve aparecer em cerca de 2 minutos. Se nada aparecer:

  1. Verifique os logs do próprio agendador — docker compose logs cron, ou kubectl get cronjobs -n studio para conferir um LAST SCHEDULE recente.
  2. Confirme que o app e o agendador compartilham o mesmo CRON_SECRET. Uma divergência aparece como 401 no log do agendador.
  3. Um 202 significa que o endpoint aceitou a chamada; não confirma que havia um agendamento a executar, então confira a visão Logs.

Concorrência

O volume de execuções agendadas é limitado por instância do app por:

VariávelPadrãoAplica-se a
SCHEDULE_EXECUTION_CONCURRENCY_LIMIT30Workflows agendados em andamento, em qualquer instalação

WORKFLOW_EXECUTION_CONCURRENCY_LIMIT, WEBHOOK_EXECUTION_CONCURRENCY_LIMIT e RESUME_EXECUTION_CONCURRENCY_LIMIT são configurações de concurrencyLimit em definições de tarefa do Trigger.dev. Elas não têm efeito a menos que TRIGGER_DEV_ENABLED esteja definido, e nem o Helm chart nem o Docker Compose configuram o Trigger.dev — então, em uma auto-hospedagem padrão, elas são inertes.

Só aumente o limite de agendamentos junto com folga de memória: as execuções concorrentes rodam no processo do app, então a vazão é limitada pela memória do pod antes de ser limitada por esse número.

Common Questions

Sim. O serviço cron roda os mesmos 18 jobs nos mesmos agendamentos que o Helm chart usa, a partir de docker/crontab. Ele precisa do CRON_SECRET; sem ele, o serviço imprime o que definir e encerra, enquanto o resto da stack continua rodando.
Não. Aponte o cron para o Service dentro do cluster ou para localhost. Se os endpoints forem acessíveis pela internet, o CRON_SECRET é o único controle que os protege.
Sim — defina cronjobs.jobs.<name>.enabled: false no Helm, ou omita a linha do crontab. A reconciliação de assentos de cobrança é a candidata habitual em uma instalação auto-hospedada. Não desative a execução de agendamentos, o processamento do outbox ou a renovação de assinaturas a menos que você tenha certeza de que não usa os recursos correspondentes.
Não. Cada CronJob faz uma única chamada HTTP ao Service do app, que balanceia a carga para uma única réplica. O concurrencyPolicy: Forbid impede que uma execução lenta se sobreponha ao tick seguinte.