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 pararesultados-import.tsque já 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 chamarecompute(manual ou automático?) — precisa confirmar fluxo nouseGestaoResultados.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 (
queryInChunkspara reads) bgSupabase(service_role) para job backgroundinscricaoMap(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
*_sessoesjá 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).