Por que a aplicação travava mesmo com queries rápidas

Por que a aplicação travava mesmo com queries rápidas

O profiling não encontrou nada. As queries estão com índice, rodam em menos de 5ms, e o cache eliminou as buscas repetidas. Mas sob carga — dez, vinte requisições simultâneas — a aplicação trava. Requisições acumulam na fila, o tempo de resposta explode, e o log mostra um erro que parece absurdo: TimeoutError: QueuePool limit of size 5 overflow 10 reached. O banco de dados não está sobrecarregado. As queries são rápidas. O problema está entre a aplicação e o banco — no pool de conexões que ninguém configurou. ...

5 de maio de 2026 · 9 min · 1717 words · Riverfount
Sua aplicação está buscando os mesmos dados várias vezes

Sua aplicação está buscando os mesmos dados várias vezes

O profiling apontou um endpoint lento. Você abre o relatório do cProfile, ordena por cumtime, e o topo está dominado por chamadas ao banco de dados. Antes de qualquer coisa: se o problema for N+1 queries, cache não é a solução — é um emplastro. N+1 se resolve na query, com joins, selectinload ou subqueries conforme o ORM. Depois disso, índices. Cache entra só se, após a query estar correta e os índices no lugar, a performance ainda não for suficiente. ...

17 de abril de 2026 · 8 min · 1678 words · Riverfount
Hypothesis encontra os bugs que seus testes ignoram

Hypothesis encontra os bugs que seus testes ignoram

A suite de testes está verde. Fixtures bem organizadas, parametrize cobrindo os casos óbvios, mocks isolando as dependências externas. Cobertura em 94%. O PR passa no CI e vai para produção. Três dias depois, um usuário reporta um comportamento estranho. Você reproduz o bug localmente com um input que nunca ocorreu a ninguém testar: uma string vazia em que se esperava pelo menos um caractere, um número negativo em que a função assumia valores positivos, uma lista com um único elemento no qual a lógica de comparação silenciosamente quebra. O teste que teria pego isso seria trivial de escrever — se alguém tivesse pensado em escrever. ...

14 de abril de 2026 · 8 min · 1637 words · Riverfount
dataclass, NamedTuple, attrs ou pydantic: qual usar de verdade?

dataclass, NamedTuple, attrs ou pydantic: qual usar de verdade?

Existe um ponto no crescimento de qualquer projeto Python em que os dicionários começam a doer. Não de vez — vai acontecendo aos poucos. Você passa um dict para uma função, a função passa para outra, e em algum momento ninguém mais sabe ao certo quais chaves estão garantidas, qual é o tipo de cada valor, ou o que acontece se uma chave estiver faltando. 1 2 3 4 def calcular_desconto(pedido: dict) -> float: # pedido tem "valor"? "valor_bruto"? "subtotal"? # "cliente" é um dict também? tem "nivel"? return pedido["valor"] * _fator(pedido["cliente"]["nivel"]) Funciona. Ninguém vai questionar em code review. O problema aparece três meses depois, quando alguém passa um pedido sem a chave "nivel" — ou quando você tenta debugar e o repr do dicionário tem quarenta chaves misturadas. ...

10 de abril de 2026 · 9 min · 1731 words · Riverfount
O .env que você não deveria ter commitado

O .env que você não deveria ter commitado

Existe uma busca no GitHub que retorna milhares de resultados úteis para um atacante: filename:.env DB_PASSWORD. Repositórios públicos com arquivos .env commitados por acidente, contendo senhas de banco, chaves de API, segredos JWT — tudo em texto claro, indexado, pesquisável. Não é incompetência. É o resultado natural de uma prática que parece razoável: colocar credenciais num arquivo, adicionar esse arquivo ao .gitignore, e confiar que o .gitignore vai proteger. Funciona até o dia que não funciona — um git add . no momento errado, um novo membro do time que clona o repo e cria o .env a partir do .env.example sem perceber que o exemplo já tem valores reais, ou um editor que cria arquivos temporários fora do padrão ignorado. ...

6 de abril de 2026 · 12 min · 2546 words · Riverfount
JWT: três erros que todo mundo comete na primeira implementação

JWT: três erros que todo mundo comete na primeira implementação

Você abre o README do PyJWT, copia o exemplo de dez linhas, gera um token, valida do outro lado — e funciona. O token tem o user_id, expira em uma hora, a assinatura bate. O que pode estar errado? Bastante coisa. JWT é um dos padrões mais mal implementados em aplicações web, não porque seja complicado, mas porque os exemplos básicos funcionam mesmo com configurações que criam vulnerabilidades sérias. O código roda, os testes passam, e os problemas aparecem meses depois — ou não aparecem, porque ninguém tentou explorar. ...

26 de março de 2026 · 9 min · 1773 words · Riverfount
A GIL finalmente saiu do caminho: o que muda com o Python 3.14 free-threaded

A GIL finalmente saiu do caminho: o que muda com o Python 3.14 free-threaded

Você tem quatro núcleos disponíveis. Seu script Python usa um. Isso nunca foi um bug — era uma decisão de design que durava desde 1992. O Python 3.14 não remove essa limitação de vez, mas dá o passo mais concreto até agora para deixá-la para trás. O que é a GIL e por que ela importa A Global Interpreter Lock é um mutex que garante que apenas uma thread execute bytecode Python por vez dentro de um processo CPython. Ela existe por uma razão pragmática: simplifica imensamente o gerenciamento de memória e a integração com extensões C, que historicamente assumem que esse lock existe. ...

23 de março de 2026 · 9 min · 1728 words · Riverfount
Injeção de dependência do jeito certo: IoC com Dishka e FastAPI

Injeção de dependência do jeito certo: IoC com Dishka e FastAPI

Você já escreveu algo assim numa aplicação FastAPI? 1 2 3 4 5 6 7 8 9 @router.get("/orders/{order_id}") async def get_order(order_id: int): db = SessionLocal() try: repo = OrderRepository(db) service = OrderService(repo, settings.TAX_RATE) return await service.get_order(order_id) finally: db.close() O código funciona. Mas há um problema sério: cada endpoint é responsável por montar sua própria árvore de dependências. Quando OrderService precisar de um CacheClient e de um EventPublisher, quem vai sofrer é quem escreve — e depois testa — cada endpoint. O FastAPI tem seu próprio sistema de Depends() que resolve parte disso, mas tem limites quando a aplicação cresce e os grafos de dependência ficam complexos. É aqui que entra o conceito de Inversão de Controle e, mais especificamente, uma biblioteca que acerta onde o Depends() tropeça: o Dishka. ...

20 de março de 2026 · 10 min · 1995 words · Riverfount
Você provavelmente não precisa desse try/finally

Você provavelmente não precisa desse try/finally

Existe um padrão que aparece em quase todo projeto Python com mais de algumas semanas de vida. Ele tem variações, mas o esqueleto é sempre o mesmo: 1 2 3 4 5 6 conn = get_db_connection() try: resultado = conn.execute(query) return resultado finally: conn.close() Funciona. Fecha a conexão mesmo se der exceção. Ninguém vai questionar em code review. O problema é que esse bloco vai se repetir em todo lugar que precisar de uma conexão — e quando a lógica de encerramento mudar (adicionar log, métricas, rollback), você vai caçar essa duplicação pelo projeto inteiro. ...

19 de março de 2026 · 7 min · 1385 words · Riverfount
Por que seu script Python consome mais memória do que deveria

Por que seu script Python consome mais memória do que deveria

Se você já usou o memory_profiler para inspecionar um script que processa arquivos grandes, provavelmente se deparou com um gráfico de consumo de RAM que sobe em escada — e não desce. O arquivo tem 500 MB, o script consome 600, 700, às vezes mais de 1 GB, e o culpado raramente é o que parece. Este artigo começa exatamente aí: num script real com consumo excessivo de memória, explica por que ele se comporta assim, e mostra como generators e itertools resolvem o problema sem mudar a lógica de negócio. ...

17 de março de 2026 · 10 min · 1927 words · Riverfount