Feito com Chinaski

Jobs em Segundo Plano

Para lotes de conteúdo muito grandes (centenas de páginas, posts ou inserções de blocos), a API síncrona de criação não é a ferramenta certa. O Chinaski traz uma fila de jobs: você submete uma requisição descrevendo o lote inteiro, um worker o processa item por item em segundo plano, e você faz polling de um único endpoint (ou dá uma olhada na tela de Jobs do admin) até os contadores se assentarem.

Submetendo um job

POST /api/jobs com uma chave de API com escopo de write e um corpo JSON de {type, items}:

  • type: exatamente um de três tipos suportados:
    • bulk_upsert_pages: cria ou atualiza páginas
    • bulk_upsert_posts: o mesmo para posts
    • bulk_create_blocks: cria novos blocos
  • items: um array não vazio de objetos de linha correspondentes ao tipo escolhido.

O endpoint responde imediatamente com {"job_id": "…", "status": "queued"}. Cada item é processado um após o outro em um worker em segundo plano, de modo que um lote de 5.000 itens custa a você uma pequena requisição em vez de uma gigante.

Forma do item (os três tipos)

Para upserts de página/post, cada item precisa no mínimo de:

  • slug + language: o par que identifica o item.
  • Se nenhuma linha existente corresponder a esse par: também title (obrigatório para criação), mais quaisquer outros campos que você queira definir; apenas colunas reais de página/post são honradas.
  • Se uma linha realmente existe: quaisquer campos fornecidos a atualizam no lugar, exceto slug e language; esses são a identidade e nunca podem ser modificados pelo job.
  • Itens com published=true são criados publicados; todo o resto permanece rascunho até que algo o publique.

Para blocos, os itens são registros simples de criação (campos como create_block os recebe).

Acompanhando um job

  • Faça polling de GET /api/jobs/:id (chave de API com escopo de leitura). A forma da resposta é fixa:
{
  "job_id": "…", "type": "bulk_upsert_pages",
  "status": "queued | running | done | failed",
  "progress": { "total": 500, "done": 312, "errors": 7 },
  "created_at": "…", "updated_at": "…",
  "result": { "completed": 493, "errors": [ … ] }
}
  • Os contadores marcam ao vivo enquanto o job roda: done sobe (ou errors para itens que falharam) em tempo real; o objeto result aparece exatamente quando o status muda para done.
  • Falhas no nível do item não fazem o job falhar: a linha continua andando, e o resultado final lista cada erro junto com o item original, para que você possa corrigir e reexecutar apenas essas linhas.
  • Os status são literais: um worker travado é marcado como failed (nunca deixado preso em queued), de modo que o polling sempre converge.

Retentando itens que falharam

Os jobs não se retentam por si mesmos. Pegue o array result.errors do job concluído, corrija as linhas com problema (slugs duplicados, título faltando, idioma bloqueado) e submeta um novo job contendo apenas esses itens: a semântica de upsert significa que os itens que já tiveram sucesso são simplesmente atualizados de novo, idempotentemente.

A tela de Jobs do admin

A tela Jobs no admin (somente Administradores) mostra os 200 jobs mais recentes, os mais novos primeiro, com o tipo, contadores de progresso ao vivo e qualquer snapshot de resultado/erro, com timestamps em UTC. Ela é somente leitura: recarregue para atualizar, e não existem controles de submissão ali; jobs são uma superfície de API por design, então o sentido da tela é simplesmente "o que a API tem feito com meu conteúdo?"

Limites que vale conhecer

  • Um job não é um build. Conteúdos submetidos pela API de jobs escrevem registros; o site estático ainda é reconstruído por seus gatilhos habituais. Depois de um job grande de blocos/conteúdo, dispare um build (pelo dashboard ou pela mesma API) como parte do mesmo passo de automação.
  • Sem agendamento. Os jobs rodam imediatamente após a submissão; não há semântica de "atrasar para depois"; a publicação agendada vive na camada de conteúdo (veja Scheduling), não nesta fila.
  • Os tipos são fixos. Os três listados acima são os únicos tipos de job; atualizações em massa (updates) de subconjuntos arbitrários e outros tipos de entidade têm seus próprios endpoints de bulk one-shot em vez de vagas de tipo de job.
  • O tamanho não é limitado no servidor. Um job pode carregar qualquer número de itens (ferramentas de lote como o bulk_import se fatiam em centenas para manter a polidez); a fila simplesmente percorre a lista.
  • Uma falha especial: se o worker não consegue conectar ao banco de dados, o job é explicitamente marcado como failed em vez de ficar pendurado em "queued", o único tipo de falha que alcança esse status no meio do caminho.

A versão curta

Lote grande = um job: uma requisição (a chave de API com write), um par de endpoints para verificar o progresso, três tipos de conteúdo que ele pode criar/atualizar em massa, relatório de erros por item, uma tela de admin com as últimas 200 linhas; e lembre-se de que ele escreve registros, não sites: faça o rebuild quando seu lote se assentar.

Leia este site em