Como funciona o FolioPress: uma página, todas as línguas
A maioria dos sites fala uma só língua. No momento em que um negócio precisa de uma segunda, as coisas complicam-se: um plugin de tradução acrescentado à pressa, uma segunda cópia do site para manter sincronizada, ou um plano mais caro só para dizer «Hello» ao lado de «Olá».
O FolioPress partiu da ideia oposta: uma página não é uma página com traduções penduradas — é todas as suas línguas ao mesmo tempo. O título, o endereço, o menu, as etiquetas, o que o Google vê: tudo existe em cada língua que escolher, desde o primeiro minuto.
Tudo começou com a vontade de substituir um CMS feito à medida, ao qual tinham sido acrescentadas várias línguas à força. Ao procurar alternativas, descobri que todas falhavam redondamente na integração de conteúdo em várias línguas num criador de sites simples de usar.
Isto é uma espreitadela aos bastidores: como tudo se encaixa, os compromissos por trás das escolhas e as coisas que se partiram pelo caminho.
Vista de pássaro
Uma visita viaja da esquerda para a direita. A torre de controlo nunca está nesse caminho. Só constrói, muda e cuida dos sites.
Uma visita a um site FolioPress dá três saltos. A Cloudflare apanha-a perto do visitante e filtra o lixo. Uma porta de entrada — o Traefik, que também trata dos certificados HTTPS — olha para o endereço e encontra o site certo. O próprio site responde, seja a partir de um edifício partilhado, onde muitos sites pequenos vivem lado a lado, seja a partir de uma casa própria, quando tem muito movimento. À parte, uma torre de controlo trata de tudo o que um visitante nunca vê: registos, faturação, endereços web, atualizações e verificações de saúde, com um pequeno zelador em cada servidor que arranca e para os sites.
Tudo isto é Python, em três camadas que escrevi: uma framework web (pystarter, construída sobre FastAPI), o sistema de gestão de conteúdos por cima (foliopress) e a torre de controlo (Forestry). Os pagamentos passam pela Polar, que atua como vendedor oficial (o chamado merchant of record), por isso o IVA europeu é dor de cabeça deles e não minha.
Cada página, cada língua
Cada língua tem o seu próprio endereço legível e, se quiser, o seu próprio domínio.
Quando uma casa de hóspedes em Lisboa escreve a sua página «Sobre», escreve-a uma vez por língua, e cada versão recebe um endereço que se lê com naturalidade nessa língua. Por dentro, uma tradução é um registo ao lado do original, não uma cópia da página: títulos, endereços, menus, etiquetas e descrições para os motores de busca existem todos por língua. Os visitantes chegam automaticamente à sua língua, e o Google fica a saber exatamente que página é qual (através de etiquetas hreflang e de um sitemap por língua), por isso a versão portuguesa aparece nas pesquisas em português. Quer o site alemão no seu próprio domínio .de? Também funciona. E quando prefere não começar de uma página em branco, um primeiro rascunho de cada tradução feito por IA está à distância de um clique: você revê, você decide.
Cada site guarda tudo isto no seu próprio pequeno ficheiro de base de dados (SQLite). Não há nenhum servidor de base de dados para gerir, o backup noturno fora do servidor é uma simples cópia de ficheiro, e um site inteiro é uma pasta que pode ser mudada, restaurada ou apagada de uma só vez.
Sites pequenos partilham, sites movimentados mudam-se
A maioria dos sites está sossegada a maior parte do tempo. Dar a cada um a sua própria maquinaria seria como arrendar uma casa inteira para alguém que aparece duas vezes por ano. Por isso, os sites pequenos partilham um edifício — um processo, dados estritamente separados — e a plataforma observa o tráfego de cada site. Quando um ganha movimento, muda-se para uma casa própria. Quando acalma durante umas semanas, volta.
Partilhar um edifício só funciona se as paredes forem sólidas. Quando chega um pedido, o processo partilhado olha para o endereço e muda para a base de dados e as definições desse site apenas durante esse pedido (usando os contextvars do Python), para que um site nunca veja os dados de outro. O contentor de cada site tem também a sua própria rede privada, com uma firewall para o tráfego de saída. E como os donos podem carregar e editar os seus próprios temas, esses modelos correm numa sandbox com limites de tempo, de volume gerado e de memória.
Acertar no que conta como «movimentado» levou algumas tentativas. Uma única newsletter, ou um crawler num pico de atividade, não deve fazer um site parecer popular. Por isso, a pontuação é o dia típico do site na última semana (a mediana), mais o nível das suas horas mais movimentadas (a hora no percentil 95), o que deixa de fora o punhado de horas mais descontroladas.
Dia de mudanças, sem fechar a loja
Cada atualização, e cada mudança entre o edifício partilhado e uma casa própria, acontece enquanto o site continua a servir os visitantes. Os engenheiros chamam-lhe deploy blue/green: uma nova cópia do site arranca ao lado da antiga, e só quando está saudável é que a porta de entrada começa a enviar-lhe pessoas. Dois detalhes tornam-no verdadeiramente impercetível. O zelador não parte do princípio de que a porta de entrada já mudou: verifica os números da própria porta de entrada até a mudança estar feita. E a cópia antiga recebe primeiro ordem para «escoar»: deixa de aceitar novos visitantes, termina o que estava a fazer e só então se desliga.
Coisas que se partiram
Nada ensina tanto sobre um sistema como vê-lo falhar. Alguns dos meus favoritos:
A vez em que deitei tudo abaixo sozinho. Para evitar que uma página lenta atrasasse todas as outras, passei a renderização das páginas para um conjunto de threads de trabalho. Depois, para confirmar que as mudanças de sites corriam sem soluços, lancei uma enxurrada de tráfego de teste contra os sites em produção. Ficaram congelados durante nove minutos, e continuaram congelados depois de o tráfego parar. Cada página segurava uma ligação à base de dados enquanto pedia uma segunda e, com dezenas de threads e um pool de quinze ligações, todas as threads acabaram à espera de outra. Entretanto, a verificação de saúde, que nunca tocava na base de dados, relatava alegremente que estava tudo bem.
A solução: pools de base de dados que não podem bloquear-se mutuamente, um limitador que transforma uma sobrecarga num rápido «tente novamente» em vez de um bloqueio (com uma quota justa para cada site, para que um site movimentado não deixe os outros à fome), uma verificação de saúde que repara num processo encravado, um watchdog que o reinicia e uma regra firme sobre onde se fazem testes de carga.
O soluço de 45 segundos. A maioria das mudanças de sites corria sem falhas, mas havia um tipo que não: se a mudança alterava as regras de encaminhamento do site, a cópia antiga e a nova descreviam por breves instantes a mesma rota de duas maneiras diferentes. A porta de entrada, sem conseguir decidir em qual acreditar, não servia nenhuma durante cerca de 45 segundos. Todas as outras partes da mudança estavam corretas, e foi precisamente por isso que demorou a detetar.
Um site minúsculo a 100% de CPU. Uma pequena loja com umas centenas de visitantes por dia esgotava constantemente o processador. Os culpados não eram os clientes, eram scanners automáticos a disparar mais de cem pedidos em dez segundos, à procura de ficheiros como /.env ou /wp-login.php que um site FolioPress nunca tem. Cada um recebia uma página «não encontrada» bonita e com design completo: cerca de 70 ms de trabalho, cem vezes seguidas.
A solução: esses pedidos recebem agora um «Not found» de nove bytes antes de qualquer trabalho a sério, e a Cloudflare trava a maioria deles antes de chegarem.
«Servidor não encontrado» para um site que estava no ar. O endereço web de um site novinho em folha é criado durante a configuração. Se alguma coisa procurasse o nome um instante cedo demais, os fornecedores de internet memorizavam «este nome não existe» durante até trinta minutos, mesmo com o site a funcionar perfeitamente. A solução foi um endereço wildcard que apanha todos os nomes, para que qualquer nome sob foliopress.io exista sempre; os nomes sem site recebem uma página simpática a dizer «não há nenhum site aqui».
Vizinhos. Alojar muitos sites lado a lado levanta perguntas a que um site isolado nunca tem de responder: o que o código de um site pode fazer a outro, e o que um site pode reclamar que não é seu. Uma revisão de segurança antes de abrir os registos encontrou alguns destes problemas. Estão todos corrigidos: cookies mais rigorosos, prova de propriedade para domínios personalizados e cada site montado na sua própria pasta separada, para que nenhum site consiga chegar aos ficheiros de outro.
O que diria a quem está a começar
- Peças aborrecidas e comprovadas levam-nos longe. SQLite, uma única framework, contentores simples. A maioria dos problemas difíceis estava nas costuras entre elas.
- Medir antes de acreditar. A pontuação de tráfego, a falha geral e os picos de CPU pareciam todos outra coisa ao início.
- Desenhar para a maioria silenciosa. A maior parte dos sites é pequena. Tornar o pequeno barato é o que torna tudo possível.
O que vem a seguir
Publicação nas redes sociais, diagramas mermaid, mas sobretudo esperar pelo feedback dos utilizadores para moldar o futuro.
Se tem um site que precisa de falar mais do que uma língua, experimente em foliopress.io — os primeiros 30 dias são gratuitos. E se é do tipo técnico, adorava saber como o teria construído.