Skip to content

03 — Recompute / Save em lote: hotpath síncrono

Ref: 00_INDEX · Frentes geradas: F3

Contexto

recompute (recalcular situação de todos os resultados após salvar faixas ou nota de corte) hoje roda dentro da Response do set_premiacao_batch / set_nota_corte / endpoint recompute. Para 2k inscrições já é desconfortável; para 8k+ vai estourar o limite de 150s do Edge runtime e cair em erro silencioso.

Evidência

E3.1 — O caminho atual

supabase/functions/_shared/resultados-compute.ts:

linha 144: comentário "tabela escalável — usar fetchAllRows"
linha 148: drena TODAS as inscrições da olimpíada
linha 166: drena resultados existentes
linha 196/201: lê configs por nível e fases
(restante: laço em JS para recomputar situação + upsert)

Tudo dentro de uma única invocação. Não há EdgeRuntime.waitUntil, não há task_id, não há tabela de sessão.

gestao-resultados/index.ts:87 despacha recompute direto: if (action === "recompute") return handleRecompute(ctx); — sem desacoplamento.

E3.2 — Outras escritas em lote no mesmo módulo

  • handleUpsertBatch (gestao-resultados/index.ts:77) — usado pela inserção de resultados via planilha; provavelmente delegado para resultados-import.ts que tem padrão de sessão (ver E3.3).
  • handleSetPremiacaoBatch (linha 86) — escrita das faixas, "leve" (≤ 10 configs por fase) → OK síncrono.
  • Depois de set_premiacao_batch, o frontend chama recompute (manual ou automático?) — precisa confirmar fluxo no useGestaoResultados.ts:435.

E3.3 — Importação de resultados já adotou parte do padrão

supabase/functions/_shared/resultados-import.ts usa:

  • batches de N em laço (queryInChunks para reads)
  • bgSupabase (service_role) para job background
  • inscricaoMap (lookup O(1) por chave canônica) — bom padrão, replicar

Falta: não vimos EdgeRuntime.waitUntil explícito no recompute (presente no fluxo de importação). Validar na próxima rodada se resultados-import.ts já usa fila persistente (importacao_resultados_sessoes existe como tabela — confirmado no inventário Supabase).

→ Já existe a infraestrutura (importacao_resultados_sessoes), só falta usá-la em recompute.

E3.4 — Tempo estimado em 8k inscrições

  • Drenagem inscrições: 8 round-trips × ~150ms = 1.2s.
  • Drenagem resultados: 8–10 chunks × ~200ms = 2s.
  • Recompute em JS: ~5ms × 8k = 40s (CPU bound).
  • Upsert: 80 chunks × ~150ms = 12s.

Total ≥ 55s em condição boa; em condição típica (latência DB, contention) >2 minutos. Limite Edge: 150s. Risco real de timeout silencioso em escolas grandes.

Hipóteses

P20 — Crítico em prazo curto. recompute síncrono vai falhar (timeout 150s) em escolas com ≥6k inscrições. Falha será silenciosa do ponto de vista da UI (usuário vê erro genérico, dados podem ficar inconsistentes entre fases/níveis).

P21 — Resolvível. A infra de sessão (importacao_resultados_sessoes, padrão useImportacaoSessao no front) já existe — basta replicar para recompute. Não exige nova tabela genérica.

P22 — Cuidado. Recompute precisa ser idempotente: rodar duas vezes não pode dar resultado diferente. Hoje é (lê config → recalcula → upsert por inscricao_id,fase_id), preservar essa propriedade na versão em fila.

O que NÃO é a causa

  • NÃO é o upsert — ele já é eficiente (onConflict: "inscricao_id,fase_id"). O gargalo é a drenagem + JS.
  • NÃO é necessidade de Redis/Cloudflare Worker. O padrão Edge + tabela *_sessoes já provou ser suficiente em Alunos.

Próximas etapas

→ Padrão a replicar em 04_ALUNOS_ESCOLA_BENCHMARK.md → Onda B do roadmap (ver 00_INDEX).