Limites conhecidos e melhorias futuras
Esta página documenta pontos que ainda não foram testados sob carga real, identificados ao raciocinar sobre um cenário de pico — por exemplo, 1000 participantes se registrando/ativando wallet ao mesmo tempo num evento. Nada aqui é um bug; são decisões de dimensionamento que fazem sentido hoje e que merecem revisão antes de um evento com público grande.
Rate limit por IP em locais de evento
Os limiters de autenticação na wallet-edge (REGISTRATION_RATE_LIMITER:
5/60s, LOGIN_RATE_LIMITER: 20/60s) usam como chave o hash do IP quando não
há token — veja Autenticação e perfis.
Isso é razoável pra internet doméstica, mas esta é uma plataforma de
evento: é comum centenas de participantes estarem atrás do mesmo Wi-Fi/NAT
do local, compartilhando um único IP público. Nesse cenário, o limite por IP
pode bloquear participantes legítimos, não só abuso.
Ideia futura: repensar a chave do limiter pra esse contexto — por exemplo, combinar IP com algum identificador de dispositivo/sessão, ou tornar o limite configurável por evento (eventos maiores, limite mais alto).
Pool de conexões do banco regional
DATABASE_POOL_MAX no wallet-api está em 5. Sob um pico de milhares de
ativações simultâneas numa única instância, isso vira fila de espera por
conexão — latência alta antes de virar erro, mas ainda um gargalo real numa
rajada extrema. Vale um teste de carga antes de assumir que o valor atual
aguenta o pico esperado, e considerar PgBouncer/pooler se múltiplas
instâncias (Cloud Run escalando horizontalmente) somarem mais conexões do que
o Supabase permite por projeto.
Outbox dispatcher: throughput sob rajada
Este é o ponto mais importante pra revisar. O dispatcher
(OutboxDispatcherService, veja o mecanismo completo em
Visão geral → diretório global de wallets)
hoje:
- Roda a cada
OUTBOX_POLL_INTERVAL_MS(5000ms). - Reivindica até
OUTBOX_BATCH_SIZElinhas por ciclo (10). - Entrega sequencialmente, uma de cada vez, dentro do lote:
for (const row of rows) {
await this.deliver(row, lockToken, maxAttempts);
}
Conta redonda do pior caso: 10 entregas por ciclo de 5s ⇒ no máximo ~2
eventos/segundo de vazão sustentada por instância, sem contar o tempo de rede
de cada chamada assinada pro wallet-control-api (que reduz esse número na
prática, já que a entrega é sequencial e cada await bloqueia a próxima).
Com 1000 wallets ativadas de uma vez, o ops.outbox_events teria 1000 linhas
pending, e drenar tudo poderia levar vários minutos — a última pessoa da
fila só apareceria em GET /v1/wallet/wallets bem depois de já ter uma wallet
ativa e funcional na região.
Importante: isso não bloqueia a ativação em si — ela é síncrona e imediata no banco regional. O atraso é só no espelho de descoberta global, que já é documentado como eventual. Mas alguns minutos de atraso numa rajada grande é bem mais que os poucos segundos assumidos hoje.
Melhorias futuras, em ordem de esforço
- Entregar o lote em paralelo (com limite de concorrência, ex.
Promise.allSettledem grupos de N), em vez doforsequencial atual — ganho imediato de vazão sem mudar nada de infraestrutura. - Aumentar
OUTBOX_BATCH_SIZEe/ou reduzirOUTBOX_POLL_INTERVAL_MSdinamicamente quando o backlog estiver alto (poll mais agressivo só enquanto houver fila). - Notificação por push (Postgres
LISTEN/NOTIFY, ou Supabase Realtime) pra acordar o dispatcher assim que uma linha é inserida, em vez de esperar o próximo poll — reduz a latência do primeiro evento do lote, mas não substitui a necessidade da outbox como rede de segurança (garantia de entrega), como já discutido nesta mesma seção da arquitetura.
Nenhuma dessas mudanças foi implementada — ficam registradas aqui como próximos passos caso um teste de carga confirme que são necessárias.